From ca031a6f045b0b376aea86dc40c4bee43206a5e8 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 27 Jan 2015 07:36:13 +0100 Subject: [PATCH] a880f1bcd3f98234a0a358e1c728c5ddee06eee3 --- dist/humans.txt | 7 +- dist/images/markitup/bold.png | Bin 249 -> 301 bytes dist/images/markitup/h1.png | Bin 223 -> 276 bytes dist/images/markitup/h4.png | Bin 240 -> 293 bytes dist/images/markitup/h5.png | Bin 251 -> 304 bytes dist/images/markitup/help.png | Bin 293 -> 351 bytes dist/images/markitup/image.png | Bin 463 -> 516 bytes dist/images/markitup/jaysalvat.png | Bin 139 -> 139 bytes dist/images/markitup/link.png | Bin 291 -> 320 bytes dist/images/markitup/list-bullet.png | Bin 181 -> 207 bytes dist/images/markitup/list-numeric.png | Bin 247 -> 321 bytes dist/images/markitup/markitup.png | Bin 14415 -> 14417 bytes dist/images/markitup/menu.png | Bin 168 -> 169 bytes dist/images/markitup/preview.png | Bin 264 -> 338 bytes dist/images/markitup/preview_ico.png | Bin 313 -> 387 bytes dist/images/markitup/quotes.png | Bin 301 -> 375 bytes dist/images/markitup/stroke.png | Bin 269 -> 331 bytes dist/index.html | 18 ++- dist/js/app-loader.js | 2 +- dist/js/app.js | 32 ++--- dist/js/app.js.map | 2 +- dist/js/templates.js | 128 ++++++++++++++++++ dist/partials/admin-memberships.html | 1 - .../admin-project-default-values.html | 1 - dist/partials/admin-project-modules.html | 1 - dist/partials/admin-project-profile.html | 1 - ...admin-project-values-issue-priorities.html | 1 - ...admin-project-values-issue-severities.html | 1 - .../admin-project-values-issue-status.html | 1 - .../admin-project-values-issue-types.html | 1 - .../admin-project-values-task-status.html | 1 - .../admin-project-values-us-points.html | 3 - .../admin-project-values-us-status.html | 1 - dist/partials/admin-roles.html | 1 - .../admin-third-parties-bitbucket.html | 1 - dist/partials/admin-third-parties-github.html | 1 - dist/partials/admin-third-parties-gitlab.html | 1 - dist/partials/backlog.html | 1 - dist/partials/cancel-account.html | 1 - dist/partials/change-email.html | 1 - .../change-password-from-recovery.html | 1 - dist/partials/contrib/main.html | 1 - dist/partials/dummy-layout.html | 0 dist/partials/error.html | 1 - dist/partials/forgot-password.html | 1 - dist/partials/index.html | 1 - dist/partials/invitation.html | 1 - dist/partials/issues-detail.html | 1 - dist/partials/issues.html | 1 - dist/partials/kanban.html | 1 - dist/partials/layout.html | 1 - dist/partials/login-layout.html | 1 - dist/partials/login.html | 1 - dist/partials/mail-notifications.html | 1 - dist/partials/not-found.html | 1 - dist/partials/permission-denied.html | 1 - dist/partials/project-colors.html | 1 - dist/partials/project.html | 1 - dist/partials/projects.html | 1 - dist/partials/register.html | 1 - dist/partials/search-issues.html | 7 - dist/partials/search.html | 1 - dist/partials/task-detail.html | 1 - dist/partials/taskboard.html | 1 - dist/partials/us-detail.html | 1 - dist/partials/user-change-password.html | 1 - dist/partials/user-profile.html | 1 - .../partials/views/components/addnewtask.html | 1 - dist/partials/views/components/addnewus.html | 1 - .../views/components/backlog-row.html | 1 - dist/partials/views/components/beta.html | 1 - dist/partials/views/components/filter.html | 1 - .../views/components/help-notion-button.html | 1 - .../views/components/kanban-task.html | 1 - .../views/components/large-summary.html | 1 - .../views/components/loading-bar.html | 1 - dist/partials/views/components/mainTitle.html | 1 - .../components/notification-message.html | 1 - .../views/components/select-color.html | 1 - .../views/components/sprint-summary.html | 1 - dist/partials/views/components/summary.html | 1 - .../views/components/taskboard-task.html | 1 - dist/partials/views/components/watchers.html | 1 - dist/partials/views/modules/admin-menu.html | 1 - .../views/modules/admin-submenu-contrib.html | 1 - .../admin-submenu-project-profile.html | 1 - .../modules/admin-submenu-project-values.html | 1 - .../views/modules/admin-submenu-roles.html | 1 - .../modules/admin-submenu-third-parties.html | 1 - .../partials/views/modules/admin-submenu.html | 1 - .../modules/admin/admin-membership-table.html | 1 - .../views/modules/admin/default-values.html | 1 - .../views/modules/admin/project-points.html | 1 - .../views/modules/admin/project-status.html | 1 - .../views/modules/admin/project-types.html | 1 - .../modules/admin/project-us-status.html | 1 - .../views/modules/backlog-filters.html | 1 - .../partials/views/modules/backlog-table.html | 1 - dist/partials/views/modules/burndown.html | 1 - .../views/modules/cancel-account-form.html | 1 - .../views/modules/category-config.html | 1 - .../views/modules/change-email-form.html | 1 - .../change-password-from-recovery-form.html | 1 - dist/partials/views/modules/colors-table.html | 1 - .../views/modules/comment-activity.html | 1 - dist/partials/views/modules/filter-tags.html | 1 - dist/partials/views/modules/filters.html | 1 - dist/partials/views/modules/forgot-form.html | 1 - .../help-notions/lightbox-generic-notion.html | 1 - ...notion-admin-project-values-us-points.html | 3 - .../views/modules/invitation-login-form.html | 1 - .../modules/invitation-register-form.html | 1 - .../views/modules/issues-filters.html | 1 - dist/partials/views/modules/issues-table.html | 1 - dist/partials/views/modules/kanban-table.html | 1 - .../views/modules/lightbox-add-member.html | 1 - .../views/modules/lightbox-ask-choice.html | 1 - .../views/modules/lightbox-assigned-to.html | 1 - .../views/modules/lightbox-attachments.html | 1 - .../views/modules/lightbox-block.html | 1 - .../views/modules/lightbox-create-issue.html | 1 - .../modules/lightbox-delete-account.html | 1 - .../modules/lightbox-delete-project.html | 1 - .../views/modules/lightbox-feedback.html | 1 - .../views/modules/lightbox-generic-ask.html | 1 - .../views/modules/lightbox-generic-error.html | 1 - .../modules/lightbox-generic-success.html | 1 - .../views/modules/lightbox-issue-bulk.html | 1 - .../views/modules/lightbox-search.html | 1 - .../modules/lightbox-sprint-add-edit.html | 1 - .../views/modules/lightbox-task-bulk.html | 1 - .../modules/lightbox-task-create-edit.html | 1 - .../views/modules/lightbox-us-bulk.html | 1 - .../modules/lightbox-us-create-edit.html | 1 - .../views/modules/lightbox-users.html | 1 - .../views/modules/list-filters-kanban.html | 1 - dist/partials/views/modules/list-filters.html | 1 - dist/partials/views/modules/loader.html | 1 - dist/partials/views/modules/login-form.html | 1 - dist/partials/views/modules/nav.html | 1 - dist/partials/views/modules/projects-nav.html | 1 - .../partials/views/modules/register-form.html | 1 - .../partials/views/modules/related-tasks.html | 1 - .../partials/views/modules/search-filter.html | 1 - dist/partials/views/modules/search-in.html | 1 - .../modules/search-result-issues-table.html | 1 - .../views/modules/search-result-table.html | 1 - dist/partials/views/modules/sprint.html | 1 - dist/partials/views/modules/sprints.html | 1 - .../views/modules/taskboard-table.html | 1 - .../views/modules/team/team-filters.html | 1 - .../views/modules/team/team-table.html | 1 - .../views/modules/user-settings-menu.html | 1 - .../mail-notifications-table.html | 1 - dist/partials/views/modules/wiki-nav.html | 0 .../views/modules/wizard-create-project.html | 1 - dist/partials/views/team/team.html | 1 - dist/partials/wiki.html | 1 - dist/styles/main.css | 2 +- dist/svg/spinner-circle.svg | 1 + 160 files changed, 169 insertions(+), 167 deletions(-) create mode 100644 dist/js/templates.js delete mode 100644 dist/partials/admin-memberships.html delete mode 100644 dist/partials/admin-project-default-values.html delete mode 100644 dist/partials/admin-project-modules.html delete mode 100644 dist/partials/admin-project-profile.html delete mode 100644 dist/partials/admin-project-values-issue-priorities.html delete mode 100644 dist/partials/admin-project-values-issue-severities.html delete mode 100644 dist/partials/admin-project-values-issue-status.html delete mode 100644 dist/partials/admin-project-values-issue-types.html delete mode 100644 dist/partials/admin-project-values-task-status.html delete mode 100644 dist/partials/admin-project-values-us-points.html delete mode 100644 dist/partials/admin-project-values-us-status.html delete mode 100644 dist/partials/admin-roles.html delete mode 100644 dist/partials/admin-third-parties-bitbucket.html delete mode 100644 dist/partials/admin-third-parties-github.html delete mode 100644 dist/partials/admin-third-parties-gitlab.html delete mode 100644 dist/partials/backlog.html delete mode 100644 dist/partials/cancel-account.html delete mode 100644 dist/partials/change-email.html delete mode 100644 dist/partials/change-password-from-recovery.html delete mode 100644 dist/partials/contrib/main.html delete mode 100644 dist/partials/dummy-layout.html delete mode 100644 dist/partials/error.html delete mode 100644 dist/partials/forgot-password.html delete mode 100644 dist/partials/index.html delete mode 100644 dist/partials/invitation.html delete mode 100644 dist/partials/issues-detail.html delete mode 100644 dist/partials/issues.html delete mode 100644 dist/partials/kanban.html delete mode 100644 dist/partials/layout.html delete mode 100644 dist/partials/login-layout.html delete mode 100644 dist/partials/login.html delete mode 100644 dist/partials/mail-notifications.html delete mode 100644 dist/partials/not-found.html delete mode 100644 dist/partials/permission-denied.html delete mode 100644 dist/partials/project-colors.html delete mode 100644 dist/partials/project.html delete mode 100644 dist/partials/projects.html delete mode 100644 dist/partials/register.html delete mode 100644 dist/partials/search-issues.html delete mode 100644 dist/partials/search.html delete mode 100644 dist/partials/task-detail.html delete mode 100644 dist/partials/taskboard.html delete mode 100644 dist/partials/us-detail.html delete mode 100644 dist/partials/user-change-password.html delete mode 100644 dist/partials/user-profile.html delete mode 100644 dist/partials/views/components/addnewtask.html delete mode 100644 dist/partials/views/components/addnewus.html delete mode 100644 dist/partials/views/components/backlog-row.html delete mode 100644 dist/partials/views/components/beta.html delete mode 100644 dist/partials/views/components/filter.html delete mode 100644 dist/partials/views/components/help-notion-button.html delete mode 100644 dist/partials/views/components/kanban-task.html delete mode 100644 dist/partials/views/components/large-summary.html delete mode 100644 dist/partials/views/components/loading-bar.html delete mode 100644 dist/partials/views/components/mainTitle.html delete mode 100644 dist/partials/views/components/notification-message.html delete mode 100644 dist/partials/views/components/select-color.html delete mode 100644 dist/partials/views/components/sprint-summary.html delete mode 100644 dist/partials/views/components/summary.html delete mode 100644 dist/partials/views/components/taskboard-task.html delete mode 100644 dist/partials/views/components/watchers.html delete mode 100644 dist/partials/views/modules/admin-menu.html delete mode 100644 dist/partials/views/modules/admin-submenu-contrib.html delete mode 100644 dist/partials/views/modules/admin-submenu-project-profile.html delete mode 100644 dist/partials/views/modules/admin-submenu-project-values.html delete mode 100644 dist/partials/views/modules/admin-submenu-roles.html delete mode 100644 dist/partials/views/modules/admin-submenu-third-parties.html delete mode 100644 dist/partials/views/modules/admin-submenu.html delete mode 100644 dist/partials/views/modules/admin/admin-membership-table.html delete mode 100644 dist/partials/views/modules/admin/default-values.html delete mode 100644 dist/partials/views/modules/admin/project-points.html delete mode 100644 dist/partials/views/modules/admin/project-status.html delete mode 100644 dist/partials/views/modules/admin/project-types.html delete mode 100644 dist/partials/views/modules/admin/project-us-status.html delete mode 100644 dist/partials/views/modules/backlog-filters.html delete mode 100644 dist/partials/views/modules/backlog-table.html delete mode 100644 dist/partials/views/modules/burndown.html delete mode 100644 dist/partials/views/modules/cancel-account-form.html delete mode 100644 dist/partials/views/modules/category-config.html delete mode 100644 dist/partials/views/modules/change-email-form.html delete mode 100644 dist/partials/views/modules/change-password-from-recovery-form.html delete mode 100644 dist/partials/views/modules/colors-table.html delete mode 100644 dist/partials/views/modules/comment-activity.html delete mode 100644 dist/partials/views/modules/filter-tags.html delete mode 100644 dist/partials/views/modules/filters.html delete mode 100644 dist/partials/views/modules/forgot-form.html delete mode 100644 dist/partials/views/modules/help-notions/lightbox-generic-notion.html delete mode 100644 dist/partials/views/modules/help-notions/lightbox-notion-admin-project-values-us-points.html delete mode 100644 dist/partials/views/modules/invitation-login-form.html delete mode 100644 dist/partials/views/modules/invitation-register-form.html delete mode 100644 dist/partials/views/modules/issues-filters.html delete mode 100644 dist/partials/views/modules/issues-table.html delete mode 100644 dist/partials/views/modules/kanban-table.html delete mode 100644 dist/partials/views/modules/lightbox-add-member.html delete mode 100644 dist/partials/views/modules/lightbox-ask-choice.html delete mode 100644 dist/partials/views/modules/lightbox-assigned-to.html delete mode 100644 dist/partials/views/modules/lightbox-attachments.html delete mode 100644 dist/partials/views/modules/lightbox-block.html delete mode 100644 dist/partials/views/modules/lightbox-create-issue.html delete mode 100644 dist/partials/views/modules/lightbox-delete-account.html delete mode 100644 dist/partials/views/modules/lightbox-delete-project.html delete mode 100644 dist/partials/views/modules/lightbox-feedback.html delete mode 100644 dist/partials/views/modules/lightbox-generic-ask.html delete mode 100644 dist/partials/views/modules/lightbox-generic-error.html delete mode 100644 dist/partials/views/modules/lightbox-generic-success.html delete mode 100644 dist/partials/views/modules/lightbox-issue-bulk.html delete mode 100644 dist/partials/views/modules/lightbox-search.html delete mode 100644 dist/partials/views/modules/lightbox-sprint-add-edit.html delete mode 100644 dist/partials/views/modules/lightbox-task-bulk.html delete mode 100644 dist/partials/views/modules/lightbox-task-create-edit.html delete mode 100644 dist/partials/views/modules/lightbox-us-bulk.html delete mode 100644 dist/partials/views/modules/lightbox-us-create-edit.html delete mode 100644 dist/partials/views/modules/lightbox-users.html delete mode 100644 dist/partials/views/modules/list-filters-kanban.html delete mode 100644 dist/partials/views/modules/list-filters.html delete mode 100644 dist/partials/views/modules/loader.html delete mode 100644 dist/partials/views/modules/login-form.html delete mode 100644 dist/partials/views/modules/nav.html delete mode 100644 dist/partials/views/modules/projects-nav.html delete mode 100644 dist/partials/views/modules/register-form.html delete mode 100644 dist/partials/views/modules/related-tasks.html delete mode 100644 dist/partials/views/modules/search-filter.html delete mode 100644 dist/partials/views/modules/search-in.html delete mode 100644 dist/partials/views/modules/search-result-issues-table.html delete mode 100644 dist/partials/views/modules/search-result-table.html delete mode 100644 dist/partials/views/modules/sprint.html delete mode 100644 dist/partials/views/modules/sprints.html delete mode 100644 dist/partials/views/modules/taskboard-table.html delete mode 100644 dist/partials/views/modules/team/team-filters.html delete mode 100644 dist/partials/views/modules/team/team-table.html delete mode 100644 dist/partials/views/modules/user-settings-menu.html delete mode 100644 dist/partials/views/modules/user-settings/mail-notifications-table.html delete mode 100644 dist/partials/views/modules/wiki-nav.html delete mode 100644 dist/partials/views/modules/wizard-create-project.html delete mode 100644 dist/partials/views/team/team.html delete mode 100644 dist/partials/wiki.html create mode 100644 dist/svg/spinner-circle.svg diff --git a/dist/humans.txt b/dist/humans.txt index 82ff42f..a612f8d 100644 --- a/dist/humans.txt +++ b/dist/humans.txt @@ -19,7 +19,7 @@ Twitter: @niwibe Location: Madrid, Russia - Taiga Engineer: Lord David Barragán Merino + Taiga Engineer & Grouchy Smurf: Lord David Barragán Merino Site: http://kaleidos.net/FFF8E7/ Twitter: @bameda Location: Madrid, Spain @@ -48,6 +48,11 @@ Site: http://kaleidos.net Twitter: @elhombretecla Location: Madrid, Spain + + Taiga UX Consultan: Esther Moreno + Site: http://kaleidos.net + Twitter: @plumilla + Location: Madrid, Spain Taiga CEO, Community Manager & Chico Almodóvar: Ricky Posner Twitter: @eposner diff --git a/dist/images/markitup/bold.png b/dist/images/markitup/bold.png index 05afce8ed7b7a8199399cfa8b46a1e4bc0386416..5890e7ed5c589d44dda168953482e20f5ff86f00 100644 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU)#3GxeO;1ZHlws7?H@{cGeEw63v=F(#lXPe z>*?YcB5^r6L4m(OQ(N1U(@2rKptwtmTakN%k--Vi#atV-KPz&dIHldaKtk(`_Ck%m zw6+;W+^ZTIjHEYhmHESE)T6;S`AMSMIFv%y8$-nYsTksVdvV&Q`ns z#30EyNwr)hc}{YZWUtR)cffp#SDfM+BV2w{Rn?co7=`Xr?O_eGb!}Ds%pl1b4sqWr z7`VY4?`?kDcY0L~GI+oO9WIjWSJmXV4DMR(cw+`FmTf#*Ul?kkYj1yobG+bblNJgq iJmLxmeGv2iKhp;k8lNj3j*`m&0000a>QWZRN6Vp?J QQWH}u3s0unOjO(l07~{0!~g&Q delta 9 QcmbQjbf0m8%EZXs01@m1&;S4c diff --git a/dist/images/markitup/h4.png b/dist/images/markitup/h4.png index fa8344a79dd4b39e8116bae66e2e0d049e4ad2eb..4e929eaf583f10cf50eb1666ff6530b9d4cc7915 100644 GIT binary patch delta 60 zcmeysxRhyviV;h?qpu?a!}=5EtX(e|7#Ji=Tq8a>QWZRN6Vp?J QQWH}u3s0unOjJA%08-r)_W%F@ delta 9 QcmZ3=^nr1L%EZVs022)a0{{R3 diff --git a/dist/images/markitup/h5.png b/dist/images/markitup/h5.png index 553a36e03972246ba6245f0d1de3c32f5cfc48e8..30cabebf7445e168a0f31b0ed68c43d54eaf017d 100644 GIT binary patch delta 60 zcmey(xPfVciV;h?qpu?a!}=5EtX(e|7#Ji=Tq8a>QWZRN6Vp?J QQWH}u3s0unOjNuD09X1I7ytkO delta 9 QcmdnM^qX;l%EZX)029arBme*a diff --git a/dist/images/markitup/help.png b/dist/images/markitup/help.png index c322ea32b6e8ced13bb7bcba0f7e8184f595a327..a00b5b6cf2c96a55ceeacf1ad56d857c020dfa72 100644 GIT binary patch delta 66 zcmZ3=bf0O0iaA@7x4R3&e-K=-cll%n1_sUokH}&M2Hxu+%;=;syMlp%fxX1j*OmP) SmpF&CCd1qdGd3!+FaiL>?Gu~; delta 10 Rcmcc5w3KOr%EmZGMgSH415N+{ diff --git a/dist/images/markitup/image.png b/dist/images/markitup/image.png index a33c43306b38641d4ff7df83ed28f25c14ed8cff..fc3c393caa3bc4371d12d0c67ffd6d333ecf1d8e 100755 GIT binary patch delta 62 zcmX@l+`=+J*_eSP-O<;Pfnog#bJnhx3=9mCC9V-A!TD(=<%vb942~)JNvR5+xryni SL8*x;m4zo$Z8j>dV*~(O#}v5$ delta 10 RcmZo+InO*nd1J&HMgSET1H=FT diff --git a/dist/images/markitup/jaysalvat.png b/dist/images/markitup/jaysalvat.png index d487f6e33f384138ce15355481d82b27a9e96372..c01ba93e858125aec1e98c3219dc77c34f02361d 100755 GIT binary patch delta 29 kcmeBX>}H%`&BSqiqOF}k%Cf-g3=9kmp00i_>zopr0EK}G1poj5 delta 29 kcmeBX>}H%`%~UaGqOF~Ptw2{S0|Nttr>mdKI;Vst0DJrhJOBUy diff --git a/dist/images/markitup/link.png b/dist/images/markitup/link.png index 11a4947fd6afe1ae90e1f8e4ce377afd719c3272..4b4485f4821185437bf3fbbf0ca6a446ceb77aa3 100755 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUk` zba4!kkX(AuoyoyK#Npub?{Ugre}2nP%DG{DnBQ;j`P>uUopEPQ9KOx|doLfc=}u8FYHFzY{_A*S0Ee&byA+YfhH X?RnXx8(1c)fr7!))z4*}Q$iB}p4Cy8 delta 275 zcmV+u0qp+30;2+u8Gi-<001BJ|6u?C0P0CZK~y-6)zdLb!$B0p;co;RQ^Yp4M@VTO zD-RGGZy-Uiu}I@#Jc6dP5} z^@dBFCOK%?D?aeFVFAZ@Y5Fy0gZ4jgghM>y;hTl__}HSOE~P)PiZ#mxGSx9pLE4pa%sv-Nk*|Dco&+<^f=W3#_ol0=wG)`Tw8k Z6DwTzBckP+!wdib002ovPDHLkV1j7^f29Bb diff --git a/dist/images/markitup/list-bullet.png b/dist/images/markitup/list-bullet.png index edd0cce79d13251626ce72c14e0c21cd3f290e14..6a82e2d6cd992424378df6416dc613eff9f937c1 100644 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUy;0kT4xmjdWt^pL=kOP}w4J5owYsw$e^LckJXz!_Jh%${(n7o8C= zeDFYI?4IzA-67Tx5d-dK>%F`PZ?vm}mBHV290nIW(cmWkj2&I^Bkj+iSl|bAV>Z{~ SHMH;m0000AX(xXQ4*Y= iR#Ki=l*&+EUaps!mtCBkSdglhUz9%kosHB)#cKeHsTmgl delta 9 QcmX@e^qp~n%EY|O02FHkLI3~& diff --git a/dist/images/markitup/markitup.png b/dist/images/markitup/markitup.png index 697e61af5d0af076a57ac3ebda6732ae109ce515..a1b02b26914aeb795890449e796b5286935729b1 100755 GIT binary patch delta 13181 zcmV-@GlI;|aM5tErvrbLNklhCgM%Je0=BB*Iz zQkP+7N4Hbv!$YPeM}%w*3fdA9Gi^d&x$7*u)D`HCnPf*}oJLPEYTA~7b+p!pO&jjQ z*QL&va$$6E=yp+sZjN5AaI(k|(}LEm3)m1yYW=#k>%!*##dWG(>U4NtiQEt@p$*{+ zmCjlDs3>5z0NQ^Iq`=dFwSkKtawOX5+rxE5Tyg^5l<-&y{VQSNADm-1WNiRLE`{&f z^^1Gkee3XP2m83Lh)Yhun-CfsEvnd1C*d6)v35NdT>{^=TP8?%J9O{6IB4C$hg?_0 zrF#W$uW11RLUs|oaebxU*mpw2y0u&0cfsq@J%e|6NWg!39K0I>12#>N2zI@a*RNf_ ze#>GPye{27y!@CK!0SYVt@q-5>JfIq z>ymTuN_T&ig{L^~iWv4)tFzf^y;0ShmP3$!zMeGH@a1+H7aiDCBv zfp8L-QE;*|OW>|au1w|opuv`aSG1Gx0(xr`Hi1^#Ceoh(y6XcIYS`=! zJ{+_zFk}k_Ev-#qAKd@&K9;kI+3Uc>(Jp_4?jgLdq$Fs7)SU&dtk=w6Eh$^pLxC0z zP|#=QUuX7WHu%ez0RdaLZV@WzL4ddKzCdP&1HXFSh0r~O_ibzawX4@ISE{kzo8mmY zGPjX4f2}cTK8yU&Dmc9+EBZESS6(hB<50|4)cxJ|6v?frrG#ZG_q z82`J3SN`0)bLPyR^KMPbX9+17#X1i!Fy8^sue|x|<^RFz$>4yGl<^xE!*b)k>;nzJw*5AE#rIrF6mW34YNk3;NjK0bvy0pZoMCW zp3s1Y+<31&{6QE=D^FW?-T&|^=5Bx8Lho?Uu1VAczaB3Kjqh>K&<)yjut}X?S;T*|vWr2;ke} z?xPFN+}6eSE4+8U2#8(L@Dj|Xrm9JG3B0>P!f*(A^n!XYk4u%0Kk)-~SIvh5Ze|cKwwK#}Je&AAMrLXeeq05cH1$ z1Nu2yg8ltbJ_>dmz#FT^DxrV#;q5+m7lz!O5Z<}>!P-#d#e5WhiYLTuWp1`Gy1hog z3l0J_;>P#reYeoviqM6-Lc5mo6nvv7o&cM%NlUx5ms+Fz|+uM}_dc8|ZEY=UTGs|((c)WV@GT82*g zP!qj<^M-(cfDN0s$L4=67_GwI&x1xUC`}0u-U!pOHwK5N8Yev~jxX366dN158Em_G zb8zssP*QLmkj)!6f=`N0)h(Db<|%F&%6Hy)V}YpNc;jtm-<}%1pdd986u5aqu=NqU z@G8bEkSH0H{pJ(hr`b{WUc_Tm2+b>3Vec^;KdtavAg$NXj>&(=d}L?4S08!AUQw_1 zC*5U%Q4=2>8M-}m`}XkYc#Uzv=s}z_{P_DJl-U7z572|dG`wNp9_)I20lFbu!y+Q+ z+dhnf*S&J{1_^BpNbsZfSvC3%&GwBOHg1cAUHq}(!5cPgPIzOCAbOAwoKzYQUJMRJ zLjiEZjo}58R3d+-I}~gUirpLy$qGmz*GeA|zXZ2Ol3E z1G63igZR)A+7%TM6i8)j#f(yY6dBB2dJ0xO+o?Kedw72pIvC~KsllO=vOd|bIvPC- z7g4lz7%0eRL1}7acx1djXdcRY(|(%vQR+2H=fh{vHt) z67pUb;tSCY3EQ=67k%b-((tO5#zqo~j*etRPp}Qw`j8ur`7j>%R&)xu(5SToohowU zX3eX-+Qxrvvt^)Xpii!c+MJRtFB4@bjO>*zRZfdDL)zZ>vKSl?m zcumjxD^9gf_Fqv19`i({t8-WQEYL=W$7=Pa3bV;%1TvY-X1z8xJk{*Sn9PU+Aq+7g z-wj~HyNkIE!E0Mz?jn49Lv(kt(B;9a#`f1!`mD$Y;sOpgcH`#A6m<$`JXM_%z9D)c z+f#oPe#Y>P!Jh%Yq_;#2#s>$Rh6?sg^{OU#Ludj7m)GSA8A+u8fL7)jip71@CW0t_&+C zPSQk2YxHK5(ZGC!-e5GFbqV3>kDjAW@QaCIG%;a2=k}wo@eDS+s1^we=?Z*->uv++ z#_Woq&o$(DCj)OvtdxJn=0SKp7N%_89L=B$`6BU6*vwv?&SPQx#_b6L1BLj81{;6) z^bTAaz9AeKvs%RA1U0)ld}I7uDjHttw^gH>cF@x8p&BjAW+A)@cz9Fu{zk%^Cw*T) zcwaf1iWmTcE!X*gl+3=d?C7F5$OKsoUMq6_ZfJl z*iDEn@BwaG8Vp>Q;8j3nN^tbsrHb{}pUIH3)247ay%LnvDjmfct8r^Ik>Q^YOW?yD#h@ zlgz7_5yw3=bmX1vzA)Ae!=Aw?$KfsVQNEJ0F+4>r7FYm!H7K-@DPPrW3>TtH2an<5 z%h~bqP$#+D&LCcuqz3#mVs9~Y(VfPMhM~nNqFN#MZzn_ zEs7?Xuz>*=BVAp;{{N&{6$vd229rq;SkUo>$)b-Z+A#wb?_`cI?C40DD7+L^oriCa z@#Dk7qT=x9mVx)96n-SY%~jF9zF>QBf?6UhRwo2o2EqQQg|VCC0lR;q?HqMziXYS7 z8u;P%Sd9a)vbr7!ZBOx2I0A1Ca9%%kB;P^-ywxdM(oDI&swp7h{hI?ZZ(@{GBmm(R z0XC6-LMSfoD1cYbpvn>9ucZ{cW*whb4u+)=UV{j;6rLbr;D*5_@Ha*kMm3^$M9xkY zFy9Yg!JCM$RN`WGhIM}iz9hOL?8Zbf@Jcq=QsWbfLPK$ZKniS=p`-w{Iy&|>xopsa z&|o_xri51vq?=ny!-ec>n0A#~BT8m)kq-f{Mp6J?pVCMs-i4@wb~}VOm1xlmpe%Zu zgttfpUesPE;gyUB5WF~YaU$Sl993YgrFt6PQb|uG;APQ@ZL@ztMCm6&RhTte;4&{B zpy7>+iaGZr8(tAp1iVGuF}@JpoiX617OAXaVjP55of5e*l43WN%4A95cO!*XxDR?G zG}NAvYGP^YmA{q{i9n@srJhqEvM7{Vb@)e5IRdXr@lmvzZ>|VlwTPp#;LQ^-%Lu`{ zPbwBj1n?e@5#fI|nJWbE-}Kl}fR0&LxD)VJh`K5fDbyo)jd+>FWj0ffKo+xF?<1d( z97P{bMBcoAD#(%D&Vbn1cNT27 zAHZr-VwXNjeC{xPD6Xmp+Z2E{uTiH}i{qOYtr;T*FVlZBs;O4_Xc7c`YCneX=3#AB zqa)#cTc^pB5D72NQ^C1Kj}YEC46gh3G0#XPCqsA*rIeduUG<+NycRva1B~hitMAwE zpC(CA&GuALQBi4BTgJ|fppP&yB8N5kQZY9!MwBgZ&~dkqFX_6;i4vvn*zrBvc_|xB zrSbzg#5sS`jtWl+jn-hJ06J<#PvVIhU#567HUY=3wxYJNskynS@v>DX8aHS)k^gvv zgjXUk{m6SktS~aj1Mt=Wcv1b&hmwI;i@L1}3i9#_$R|uU76I=8bSCj}Kw{!)2ro@3 zVs;-#2N>-;4&jxy)PIs;gT)|er2yXkpE!#uDGPrg;<--qpVMJfcn)wpK1RlN-msWB zQEvpd>h0p&V|-Xd46KVp6&JN*U**bvjPnu}dneMQ1jkCS%NhpIyox^dxuQ@^=a$A$ z*R*=hIB)N9Q{Qd9Vb!WNTD$&Y z0I+{TcoWIzLS7GYbU++l%22uRir4-myp8}%VoJ(P#tlZQ=RtS+>nH}9nA5C2dimsE zzKYrrBZ1iM;oD>Udl7NT2lk1Ux-T&*;(%r46qTHY_fEleMr!o}h=*cfY`lj5cD2UR zuxcEUoF`X$yxUZjhgw*;zAD(D0Psq730!}^mLjbD0lbesQKKoK!7N}gsx4*UrC8@; zOY{f;cpsj7Fp(7ipdaEH`gH)oE6%F`-nV%@092ETdP;>2l}47Mnh4}rSQ;+_c+FgR zD@a%we?_d4K`x?|x*^OJmP)I&s=B(SzTskW6lHP z5_j!%3SSD{WD$Y08WVMpg)V@1xhA#CP{q;vp$F{ZwHm6eW^)tW`)>Ljkw{6}~Bt zfp;Ghyu$jQ^4EO`-hEQUQaXJ2;6Z-~ugM_Q0bu%shF8*1O;-WD6=qH#KpHE_E30da zKouNmb!}b!wT2swjlVTFx3spkwYPV4*e>meIY4m}b70vc+>Abe@6nj3#C_td0eqtz z#}}b{;NU)SCCBYKcy8rb6)W)#z}vO7^5HeWpm*q^RjXQ>ers%~udS-AFz9~@V9%Al zeikRkM?SW(0&l$9JoWN^GF81){z(ChpoL_?0dA+fv6>4>3 zMILX&0FAI(0lWubM3^jQtpMKdk|l^`3&CqPNHnlm@S4PfRzNF)*UUoIMBfe&Rm5s_ zO>Ny}#A;I$!zy3@y|5#Z1}A?e=M{cRtMY|ezZ{L*lPG~3z&FM*d;z+<;y@K7uH?A5 zoOADR&}HBi3j2D#Z4Ap-PH*Pf6)j!*7 zStZcvOff(Kyx$)X!8Mbs!-o;P5Hho9xJtomW#WJe3nyeXb7Ni-RV%X9s|2g0uVPTO zb&zT&A8l>l?qFJ!d%nYbudU*R*MIpgc~7DQat9A4$3)o07owXeSv@7kB_FK>=<@Tr zmTQO+2Ya#V?VwF$_i=yg`+`^H>`5ppcM9UBCPB{Rplb%axfWQ1v==wTKqUH4KFna_(rtGz)JAa>8*|L&IX#*-|eNDK-Z5;z)LjP4q<@>$~k<9 z5)n4Q3SGoi8F(uVcy}fu0IRjJ-&4O4to{aVwH0rxwhjhb3Ri!wY|URr(Fe0H?(|S> zF1Giq|9p2~PqJiq1n?a%g)cxiD)C^ZR0*FaAN^&~SYbl=Q_J&UGgq&*!>&dP;!|mQ z$st!1$ci?lG-TEXetiUCA<4hG9_se?s&&EP}16>gp;B9Rk$V16EV0Dx`*wcd;FJ0<8X5s z`n_|l34}h4l@esCHAR&**BUNY8`vYQf@~}ByvR~>x#3!^MItpI&xysy6|b2|W(n7X zkHk~0$w$_&v7s62s)=Y+73rh}^IO1g5H{3l_1N5&A|u;*6>p`g$&6QG@SxOkjT@Ce zG%p7cn<*hM)||7CjkxmbuQzZ0`pZ!QRlW`%{pHq8q+f4d8UDvblO7ouf0{tO-`3XJ zghBum1MomqDJf#vtn$&cjUy-Pd9T6KYrC{3@i5I#&YO>lUL%0-=|i7O;hULxKm^|& z<6j2o<{TE~oF~)b$Jf)Gn*~E}PAhf62hc!VB7Kdk!-2 z9(_e(2Cc$l*5%U&0ltStAw&DUCH zd#jWRrTgp~X7PAHYpid6*V`RzryAE>RV3OIu+-ggczvvSoDNn-<|))h{XZ(gz{+D* zFAgtz9s&zq`IORle*-&pu+&uB!i#Kr&p3LRVwR_~uX=GXY_q?9MFsZf< zvich^R-Ub{VV^aHKQ{_s%(dM{Zl{R$5(U!)odlk&nG$ z%)`KoLe`}oj(1%9REZ^Mnv;Pq!WI}~eh#kBl;4~^B~ zL#OR6ZVKENf8m=c#^Pac2Oo@K&(s`oFb>|;BHM$wD%l})CE>L;&Su^}tWGE9sFgR~ zWzMhSb&HmWRq389dLY0$OnglcVqF1dp&XwodW?W;raHrG#71)2pnveGHBh-&{FE#7 z#!mpeMMm5}tVwTPL>;S#H9pVGbds73rmCiig6V-XfBv1x4+ls}&-JAv3ldqL@#Y*~ zCiu21l|K^)@O+g6uX2qYc;(MohA42Flu-uFkyi-`Wsj@*Q!fpX`-3jXQMEb7saPTUg83We@Ay$f5 zFlo~0e=)=&BR3cd zt1rrE1UIol2=DPsiqpfHKiX;8l#dAtjQjw}gHuCv^r3uPAUFc>V7P-if@$Th?IOYZpIfJn_)+R}>CKc?ypyzn;rEBmw2u z47?*n;YH}q@^-XW3c`zbRBZ(Z-q$PgLM3dVUqf9At$Cvr<3X}EfDqJ%YIWK?} zdF$7-w*r-4Aj$mGvNPpuWNDRke+j%D6uc5KFE8Yk$tMcp23za5$@EQ`lX=dGFQZ`a z#gWN{S8(5h=<6^*cb2y^>mADd%vvHy8Fp5 zL~95bSO!aU&6~`6b+pD{v)Q^R&AR)Xz0AfpiAjI<4Q>T8W;XPHxg_cywy@Qw6S1BKdX|H{Kh$bsD z^MX@Lijw$dIsh+509{Y#mg zCh;`{EM^l70x)y2j2w84e_~TzV656Yn_uA%ylk*=<_}QM4G7+6t+7QGxmCZ3?6%;=BwF#{tr8mw;K9pYmx$8?f1qdJ^{9!B)>}-1 zh*e*zD}@a;fUikp%8Rj*fp>*bbjAx{ca^6AyMb2?WI{HPG)TI;-k^hBChp7Q3#^qe z%eAHkrVhd^*QV;aDRLaVXIOsv1It&-8F&IcxkGY4e%>mjf=Uj&L#y>7Ljk5ma!yu4rAV~O!28Vd*c9M) zg0-|jSr)6+VnXX@iOqLm!)p>t%{E)>ak1*a`Xcr;8xtCft*WlBt-H2Lu2@uA)6&XM z9c-^}cmWslo+&942ohTU69aDvN5!NH%kCAt{`^|m)5hzYf3vk;IK%*z>3DmMrBTQ2 zIq%tTe-P^1FWwtJ-dT7pdBOo!7^xQV;VsqUSH0lEE1xU^uhBrk>;7@P+F};is=-iM zN6f*jw}O9|%y?Jj!Yi0XXd%+FsvEsAM?0{=LQEgHOr^Qfse^NrK6Q&ZKFFD z-jcEt7;7zIF5oRI#;UO7z6l$=`Du~1)-&JGIF)>R!TB!_9RKp?U*pjHfd%hRoJInz zZx1_@P9hqArcqaz1r00%0IqHJ)QJ;kzuVT_P*ow~s%9$#??1`3Y%+O}6+xS8XW=}< zy{!fLDkjg>e@gwec0meZN4w4TTV0b%2=A#9F0+)qvfw>Y$VQe{zH{)}?q!Y2dhto*P+WJrJuuVQkg zp1phkW3Pr90$v}Jnmr6a1*ztmrr90}_+2Ur_lc{UYAa0qnJ$E@S~!=jRsw=oGvj zod>TEptnH~HrzbHfK^t0so(9Bbt5i+G{0qFo|8N*_T;UUf2^}+5NnqSgUG? zsV5-N2?YviYh}Tke+00KejS0- z=I7?ZpWGwPz}wF0oOPfdOllC0cSp;o^1=q2?NUC|zgKc*rW5V89t64~SeBHNA|x^s zT#dm<=VTMU3i|;7tJmm&K(!i^XCxs#UU4o1EKAv0XPkkz!@IMbx2@fiKf>15#x0}c zVm?Ds@!6Sjr_eols$7gp4!o!GQSYHppv`;I34G;~t&_zhDu3KSOm#t12qCL;sE>1B zBdq=jJ8kEWCE179e~wKQA6rXZ<1;*X%kn8)NgW|PHlKmFkPB^Y7O9M~5l+C{K8~9@ zc?a;e@^c&huZ`!tZ9nGIB%LV!$L)*Yin75l*W?c z{Nf8UX?P!CRS&usj02MijzSm9Dg<9VAvY# zINcY$XB^8FC=2~i@IEx}2!NHqm8-P<^T=cEJEV^tyR@~ptY#g{GpkzKZMO|?b1OIK z9oxc-^KG{Z3r{c|Ck~CT5$K*2C$R+F;y+!VHHb3~ckAck?A+p#VlkaOSqSm%VHaMJ z#jmQ^S!J@JwI*8sY?Cq&5w%FoCJ=z1$~Njx_%-6i|wr7 zhv&Sa0ch)@F{J#O#Yk*zLK}=8L(khD2={S}pJ=6vhE63SO4w-o1eW+z_rYFXLq;u5 z&%h}?egBaOUS3|kWU}rvj->IZrC|iMd5 zYx09f?4yv%=WVTPWC90|#%pc7sGdw++zR|cPB8H1=Sp`rKy));_x2Gn`ts8=$}Y`% zK`DQcLOJXD*^IPY)EO=i>cIi{et{WvQ!diOwQll^Xz>{)*@|AMwSZU*hitbEYrM=_ zo`u~J(AIbZs$~rcFFTT?#;?$mriL3g8k+Fl*WS8Xv{@Z@Erm0eo-g3{jH`$Vzkx7@7Rl3JcM;s;#ZR43aAwe^?&8?NX)KBnzWoXPj614HUc*4oDX2`KNig z>Dk%%c!1s}1nk&X?`2w&y&1F%k% zlbtIUe=Ztc`+G&E3o54CLB#XV^RnzRNx)m?1ibERIyyym-~|`8t?6=YO&u--0qwQ@ zSqv~`V(m2o-FykyveVN_E;_RE0y*~>;+v60kKzaf@r`2Rt6bGYqy*xZX=SQ@0lbn6 zTHGeQ9k!^cw%P6lyi#LWPQv@*e<@730RBs3d3Ff}uhReSz)M`{4y=#c z{`+GR15A4PNHKIjPiKu6Vn9oC0$mE}TQ2@3i6#1>ALbJ8oD% z849z?6i@hkTv^j#qKh@Ew;{vSM=Z|={|qKmGOe>cE)@9wmW4AFCzot;)Tz^RJruEC2M6P55Q zaIKeHY@Ku|ZwFqfu?jJGd4`JM?Y*pw`FlpXpko-AR0adD$32G^wAYgM)5Cyi*_ig4 zVjlQ=hWHJczIS&PKvyNZ9Vr36g}VX1qV%Sv{r!H07glF2zcn_swA(s~-P?m#e|oF} z!3$4hy0{21X51~zucW_kHbbgotB#0_@> z?|;vH${blz38uZKn326-^w^U=e@*}C<`k7&b_Y_vu=3)O-FpT7kCg5`ytdnY@ovEj z4%Q|CFXKLfK!8lxEl2S7zH}~)0hSTdm7jZxfmgN0p+mQI9lUMDyBSQ9%Ad!TlUd(+Z81Ky4T{yUfD#OBUO7B!h0)yFN>2O2RIIIdeWy!XF3C265pS*b|+!+z31@y```EQ z%9L{?;60LojRjabMZnwl%Fh|O99-E+Q^$@K7P8^BZ@o6#8hc|Iw+}C9ukB4rr)f-I z*56@xlXmYvd%cs;MQ493e+VA-CZ!4az4!2X-Zgq}8(vY8AiUpX3xMT0>lp%G*@)}s zSZP|v0I?cC7I1 zOAoOp^V;mNt5Dn-yppYr|Ni(XV|7W#M#~(47ofX4?M!E*OXItnk8c;lE4Pcu8kL<< ztd5S(>Tz%eUWH&CFPjLw$8b?V;W3uZlJLrUUB7uYw~(flGs(N8u;k*Em%4Fg^GeO- z@b{EU%^r3DUdgj+e``O%h8Ndf6JQ< zwmDNfIu%~I)6R<$(ZrpX3>M%dOqdhM1DS?b)@SCe3x$OxW#z=81oYw>WhKRB7p~u$ z*^3LuRFTsH^P^ObTr^2|*Z50K@NdrE&0wAz`LmFOB4}bB~emyCP9v#@9ft`HG z>E{LLmS5>Ye{@lg``B9m-z0MW9}C_!HpfK3>uqnd4x56i`s@e|!N@)5V1fgb7Yx6! zbDXVHG>%mvOA9k)(;c^+cb`jF?2Ca{<~DNW%}W=`i(%LR*H8kFr_Noxa`V>Ak-c!2 zi+5L}eVa%jqO^O&9tz1tb(G`$1*aXoZ>sl$`6?-Y5^j%H`C z*5H=d@x+x#d~voNahAmCJ96c%>;JiU;oMoEpMD15-n_LEk1k5E;!dQp&GBYNtrS!3 z9kEJbe`nbIx{YtbPSu!3!FC%jm@O(MXsxmb-e(-H_xT-P0ND( zQt-;CZ$Gmm^32KYZb%-9+`;Y8rXJoC=lHK7G-v8KZ+GfDjO5Br5%W_)i_@>CV|RyBAHSu)AiTT;(y2 zKJDlu;CXuN?@T5}`hILaB+P99+rX^HvMaOh3cBPxd4O+HMs8Nd-v`L+Y)6Sgr5oJswMn?LNLq*^P2lN1RFg21n#{f%8$^g8HI(*o^YK_m+q#NtE%DpoYhSt#@kZ+ zA$%SCt%&j$OA6_Hx5Bc&KH@r^F5OM3IvT61tE=i;#isc*fS0Rl8s}i(?LLE*fAx0k z%uKoKbh>m`;ay{sSb&2F9Dr;%cpqCvWWEvKe)7}vE_hwK%kXyCnR`uUGGNH;d$xr6 z7OJv~uJ)QscO71bGzZh$_59Dp)R%vkmy}&{wbxwgJoWMFNj>!f>U4Pfue^Bf0;!*V zzV2$T-S_hHrPcHP-cz?F=a*1B*argsUvGC3vqEnzM_0PxQD0wjzYB?T|w#L}*NdGFIoNA32xLL2z(|QA=(51a_jE&L(IpI~;@m!7L!Kt# zrAlzY`@0mp{19F@FE4;d&-pNZm<|Yoc6{C!1{Ge&=MdXoM0_!r^u7tuj|VS-e;P&p ziF`_zj$ZU4qSPg@vS%E;e;fKIgb;-;zA|=M;FIQ0hi_y`@FjsAMMgR75?t{9ZpFmA z(-AZ0Cje+5#-qHJoS!}zIpY%8p6jz@lozPt&(oOu!e-R@>EQVgz|xWlUS1^IWE%@| zw*>tKa<*hX@m@mE&b{VC^x!7by=3gNC}vqD3?|_9BL8xpU4jc8fv=8N&PfzgmBDV&QOF$Lx1z+k$yxwz^@2Kg7O%fUf?*oV!Vasma*v&%t_os=- z!i$pA%YZ}Vkrcn7okCA^r*oUHZH z8_u)g^`(Lis)@yhe-~ByOGddd@UqH+&!6U&Afta%e_@s2g7Yj5?&x;OQW|b$fcrl0FbrXl#98Bd#05rzh-g9nwwae+IDfbwj)_dAg66FM;5Y zZu5zE$mpA)+XNIt!)BJ38@oN{b$+@VydC-wHp?xm&wOG_RtbZNaC#KnXgcciWtHH9 z_xGtjbX85q4fBa-sIvhYX*V)f@MXp``cUD6FWtvL2OW&{PDlS<(vuhyJKu*rGDdE` zgzVbz6_&*8e85jP z*nS#}Mv{Bd1InhuNTLKzTNjR5-mY3Q|SP600000NkvXXu0mjfN)wy~ delta 13133 zcmV-TGqTLlaL;hCrvrbJNkl z&Ux<7bDn2r6ui96w_rx*nKRGj^L)?mobx+pWHOgra>=E;mHdB^UW12tc?}ud>rvOq zaH-2Mv!gpH^U)#GlOsa51qE#liJ3mJuiSN(UFr&S$4<7Ru}-6>7(IP!zXi!Oohx~&tXyB)gsT@tkZ&?BxZ z;?n(sx7YN503o}G-nhO}Z|plUV*R?UAGqLk>At}`JS2Z$0}kGefdQK*N(8%J$s5*f z*syhp3tpG*9A19R3*dF4!Pa|8V8BMa0t0fy;)d?Srw6TDzd10#1+Pm^!z&?Y;oXRh z8W6nupTNKAPxB(ytqa^72;lwT3D*^Isng&McPean;wuSw5B?GNmOqb<3s@Jh8TAOe z;C0D4c%^^4%ED8eao#7EY!M3^Hg5b11FwAe^v&zm2W<{?!Ru0I!~0pJQ}90WVQ|2P zK&&jMG1o1q>OczdwrBItg?`&y^MyF6AD-pKR(*4U#H-w%N3QVQJu zFu>dEmB1iUuWWwBMeqHEH}W$9vWy~A-f{xoM_+#~+K7c0#0A=!ygr7}`vcc+*vzo| zkia`4aXoWK22StoV(9+DE3O0puQUC;fBGdlAP_~co4E>zuHp<*!0xg28-h3r-2UN1 z0PpbK%x-TEJT}0^(1Q%G6V5ApWL9Nx03Te)?pEt8R@BhF*YvRU0YN-%ei-1D&kNbi z?D2orHjM)>W+LTCdS@0qcXd zvbfy}1mOMPPY?VF>pqX!@2!EmC%ZD0AAkm10$$Nh!VBoFP1p=tZJSAd0_biCOsHYA zJNQV@`oNH_6tuK9hkf|q!}~zM7Jt0aAAsys}=iezl}*-2eqz zG(bV0nSY(ti`n4MUj_th+qPAxpoan8zWW229S;0zlnbHz2=6=A`s>%OU#V1My*I^q zcx7%QXZ>1Z(tH;A&+Xg)`I%Z@_3NsUZtO0JCEMBPZle|S&xZis5pkPYx7!B;ABcaQ z>M`MW39tNx_vX%>Gxxokl+O}UFp6~^USPfhMyy`i1{Bq^jUsuf<)r<4$qaW^K z5xXq}{vd6A2;h}Z+!aLc`qu69{)gtL$9+Wim8}zc{VwTMKn=4-rr_b#ynQF_>2AHB z97SlrBW}Fc9{n(kq?M27sTBhOgJ{Dy0fqhS z(5LACJSaAMEp%ID$!fE|Cbyz}@|cHy;i zQdFSm-n}0|A|D=M{i`>WOokqw{BRdZYuGNfBEoimIDps^ZEWuo6%Jl4h5c<5^f?&_ zi~^jKWy_Wkr&!Ql3!`g|UE5-2Dj0Y}$fH8|-V1cM0d#kfH$Dxo;~d7M7-j2XBID*_(pHQ;n0K7snTD4T_Bo-2%4V zvL!fpdnhTm4#<{Go4_YUr|K3?9{UWp4CT9TzPV6TZ@&2svv1FgSy+%72@2e@G1&T; zU3e8^7fO^2%6{vq?$hn4doSWKDum{htFZT(jh|KcEtJ;lXvcr#V?VaD-D{6MX0NE% z`jhUm(5Q)zjtt!qx?@LpbiBs6aLgdi8GiDE5X$TTya(yQVH(~ra1VApz5v~jZDA1+ z^lcwT!RubRWut^P1tj=U`>Y!Cre?>cjhnVd!Y=;U@ZgObw zg^MWKIt&!#v#>NZGCVR~tu4}*mX_ve5+cK+H6M+6j&*{c_$nlfMrIq`UIXyPFn^B- z3ki9@3-N{MhJ@|jy_-IByJ&b-%VHx5MMp<6q9@pfYkkNK$9@zKd@DKyTxitVfld{< zX^ZAHUTuHlKDi(q(3${=NFlgT#|CeVUN#InY_LePW8;=^5FQXb@p`Xlu+*Q00)DlV zhcVuutV#GRL0s`wUK>fDsgC|FPg*+FWb=HZG0#^b2L`B5_?IwQ|5s@=o^%l8zU^lhYo@!}nw4b1Z zQM|5a{S~L$r~9ug0*`s3($%>ud=_e>!(+92Q-#@NG6I=QX0u)!8=h+RV@zhm!4QU+ zknaYt;oZ&LhTyeruXGWDScMt191U|8@p*sWQsb4GoGqW3EvpK zi0yx=3O{4`rr^(jU(#D52IGT+O+y9yrg}{iyfHKZg3If2g^Z+90Kp${F%v?!?9lnq z_ll}Ut&xzrn%FP*72%r_w3M5xh45-H@D@liqOk&a<044-5RvGSR7^}%%!f~oI2HjB zjbbZ?qc}n_F<%W=y?zf1K%#BYB>rMi{R5%8LH^dAiv>FS>Dx03faBUgr% zlO}7TqcwW7$!K6cLT@md&ANne^~WzzC-|krFq)XKUGw_U*LWryUQ~;Og>(hJz;(9+ zbYpf$(B~R*yo-T1C05G6V)G!p9*a`8Y>8&jg?y3tCTwA^PUo>Ge$$Qwfq_DNLxX<} ze0m2i3*Q(Hj9D$>aDtj$9lk04Z50i#^xLXYO*?4Wj!=!3WwQ|81U$T{d4DD0&6B<_ zAiOam@c@K5VmEZ&T@f*k2|904UO`b&0Z8_W`;IO4+vnp}eAk z*l3M`AeYBEz&Ae9IE4t#YxBp7Eof-r-t&5M=7|lilR=|C=(Rr_->-pq7*4-C& zh)L#E%#7n68anb$c3&9lhGEZOl;iLg`6ypa*%Y3l77Hu@y&4o+$ds>XHiZk(rGv-t z@D=R%c&I)&(kXNaL_?!V?}dNxN`?)rtN36yHSXo^Ugm$F(DI9^f1~{*uI+Aap0N&~pEor7)U)2DiVP3 ziU6BPKOqzscMQO*XHeyc@YhlbUbBwRD+j|;2(LkeSqe`OF>u3R6ZjjW3Zoj)J0fQn z3z+W*u;5L^S1NHayTX4u178wd5q4vu7&S{)txx?DDB zVQ8=&5>vt}2GY%~W#K}0HB7rotq~lkiH$0|;Imxi}H1tUZ>glG67aHU#kPOhAfogWp(@N8EpVBa z4$|<(Ma7(dnhmdrDFWUi?iyc+?yeYcQ;SqqF)f7rT92n%{NyBuUf=WS@7lwm}P|E z-7ggjBm#I(#E5_Jn#>h~_pf?vC_u-oE8PirD@0wDh!pA(yhglC;xe15M<9z?t@n{n zOpc6<@hSimi`I-4gO`8l8P!y)d^8CHKDD1fc=NEf zs?m|~zN6FRNr;3O=c(Y_qDKgC90u3@`7?H!8e5sfh7bD6RIOw=L$Cq^7pghp$yQ2-saq9^f0jW1KY6`O!#S6flr*wozI)Of|J6O9|Rn#jLD zM#3u*n11ZNFjg2D_T^8;gMVAUc!yI3O|c41|}a z6fwJ>ql1k0pMda6Tk1c^u)$)Gv{C?X|4*Gom6U&l5b<26`Old!Dm(``o){}*J8xJ_ zoTxW~TlG%y?J*%NA_mq)qKb>!xxaE%KgM|pi@h6ZQi5Y8*kug^XkJ4f`$ADDrgKYU zsB2m?cf7av_-XI8-n44f8ZF*>V~s<>uGdMitJSRhUrmb8VM%!Lj*4+!T-U3%3c)KH z3IKmtA-sv?b0M#XI65c}FJ-7)c*Sdf5?)7uB{3ysCgTPp)$^b`^K}%1Ow1WpAH96a zFJDFNjFCX>&hYIq;r)oX-qAYN|?3!+W>jIwQ4uA;d$mC^lZhf4f>^ zX;?j;NY0ZhJ>F}o%0n$ITwfJzPyl!(y99r(Tu%{J{s7*`pQ_Om&|ns@7}b_C@KUUE zu_by00KAXRJCw)@0MHNd4E;KY;1%ap0Pj1z9ssIIMLng$hDsyLQB4GLEG&&z0K8@{ zycHy@jK3mQ$siZeO5G6V3QMKcT2)7f z@lDn|F+4SY`2&C#*A>9nsKv-PSOBQD0Kr=X-IRz2*p8|v;C=kB71k;wtD%6~{|euf z$H2Rv30`6SPxHsi(O2aE@sHSTG-U>4(5Fm|}U^8n_F7j+S=PYI&7DB#vG)$i8;9ZF>Xd5!1q{8RN{Vd)&Ray zj^m5aJ$PupxRT@c9y-5joQjqB2H@>lTKVuAV9+~s@#@trO}{lZ)Yn#3Rv3SD1+eEz zUq73Z<0Bu}Sb;ZQZJv5XKbfjtD*vPaM$ko!tx}>W zx~8`73SzaXiD8wm|6bggNP~Y9lk+M+rB(Uj>|c(>?M;-x4d5H&7`_1A-Ep7_5?69u zT+aD-Ip{L*3WfqYPg*UztF;tH{@oQS4^QuL)8@=sv$~}jKzs#2T(g>&pQe~yQzY71 zH4qOkO=(eHN(v@VAWygQ@uzDw`0=bf!@I;TJmX1dPNhbtXT}Rkb%uZHhMPAV>*}BH zwY(DOOr{v10N(Epir|{b)sZ6zUI>|4G+d?NwK8!)g@qHcnz=DAiK-RZ>NSE@(pNF4 z+B!(JlaIExZ+9{+%DvxVzSmaq;v2twm%KMo0=Ywnl4Bz5;tSDDl&qeTa`q$?l{*D-QGamd_vQf2?(g>UET9`FB;X|)Y=^PH0_7Yz zOo<2^V1+K?stml92E02H5rEa&*zcL&2v&cCw%UrfRa*xGErow8SGMLaqv(U#A9rRb zHW%A__J6)RxHnlcJOcPmkir+B8ui|laKwfc$_dH{FxPbu$imZ+F@6t1@Wmg zz2uN93S>o_QW`SrgFll><>BoioaeLHpyk^t@u;=<$eyXwfq>3pG3&&D#n@{R0k58$ zJU}K46tLix%VmGht%%nc*@*+Cl{crV6vRxLUOjud^;&*R#9cGbJTcH(`TTqRiTP^m<0wVfpZ zr~f2xPtWml8PDaxd+Tr z+Jr&?6a(-;RVgWA*{t%>w2dbx>v^xm(`&oDH}MF~PtIG9i(Vsu@0r7&OW~WDc~Au3 z9ur;x=;j;|<(@!yl{bDGPWNHsp;lK&xN4F0X3LuQ=DgR|SeYkICETu|8E&_xsg_Ro z=MMz{cvX(iZJkn?Cx`|JpMNz@k#&C&?fSHOeUTKgrJOV@o&FyH-aG?#C{|};!K?7o zq?%ZngZk2nE33Kt-h2MBLwss;&`-{}KlUDp7SXwSf(P%HgfhRoI*QWBUUGODyeBmp zON}UCt*`)Jg)J-C4bTX})inrSxyN|4-C9h%N^(AcT{rniPUaC2Wo8~m=#H1RJGq}ujUQhqy8TkVPNGk zs~3ltJr98euY780ynlh6I#_C|ZQ(^Wy=NXfLNUwJIdYX#xB15auQakO{d;~-VVG1~ z2U-0M7%R_K*Rs!=!k-%jFy`8BBezq`m4bIXtFZAHdfRPn-|uChO2)O<`0fkvJ(4K~ zB8Zmwu`h7lnB>eab23FmpgYc9O)d8`h*4Q&ZCv9?hN;Tc)_)?ATq~`vvSAH%i^#{_ zH0EL8MIq}l563&MeX7I~v`tg!z-I-Gtlo~Ge;OdX1^6*ootc66g^GBcnUzAIH&!=! z%P{a_g8~}fN9P{{pnm-|0qoa|a*oXxtazaGw_ycv62Oa>WAOU3n;nX^xMEuVy_d%7 z$l)`i>;-rp1b@DnVk{m3ckrPY_DszYhvMK}EwVj`tCAf;R}x-p;~eJw!|HTmj#_#1 zJ?8u>-mqwiSe5R%q6Y%3!^GDFA=VXO7RvFdqQ?lhW~wv1PHZHX4f;EuS_74f#ZS3H zZ~PR%TV%uy#G3Tx#niESSmX1|Oed+yV5(}GB$ysJ^MBu&{BVGz^n71BvLKP=8E?*s z<$`a!Qu#A+0MA!B@G95ZfmaUh0}12x zg_9?b8GlPGGU8(`(qY4ZQq$|yVfFuesYG@*6|a_(;|rxQY^bN<h47j*`1#Trvk!a!7903O zRz;+(mcGj_a9ABaRMqK<1n?@Jhs$52##3Ku9UC8?sww?w@>rF8Xq8Tfj{wXxyo3HO zosWfb3{4eQYgG+s{?u7NeeCIaoe4V(OT(*t2ZZ_+Oxl3SWNnxutiS-gIqXn?u~-(o zCx1v>za{iTIjOT)ctwHZ!0Ufk@J`|_-m(_cUc2-;+BQ2_T+nEk5iezkjA! zaPUGX4IFq?pXx<=t#llClLt>J3IC6Me!7f;vrnWGZL}inyue4F+EFUHJTL zfbR9C)-`j+d3$-*12m!}yz(jfR8u8Ax>ZqOvR+$_Yi1(n1+XG- z{hIbxpz@0(nSWeb*#TR}p2e*nam{6L81t*1}_Ov8J+j0-KPlKTfQudh-*9@Ad?`Y=saX68kw zmJ}uN&2#`>i~zcx&Mnmm;T4Rn674Gvyr2bDATktSG6A9%%J;mjYPo*NLn&s$@QEOd(wmSxfD{BRX# z@8##%#FBUdj>~?y$b=0fttZRMPMrcjCkfp@c-N}<@Cu#xMrIC;Q|8yp`#HIAs{7Pc z7ym764Swi%b8?CpP1QDyg zR96ZcY5-r8$dngjB?IqDqv(tm!0u{K0d@ng8OVfeB59CxcfCOeyG-0y#1~jAVU}x6 z4NM(`S*}ghbyMXyc+ax@^aqx&mNW2{pX90p2>dQCe^B6+c?;pa`~_3(A35_dCJ-dF{3iz95{`;V6_(vEc>VdcvZsyLH)m_Vcz>7yD%0`y8cU;3*mK@< z-~J%fw_m(JVS=;pTJnSgtT0k7;=^02$FF+9g;zdB1YVZnt_Tng~(Vg(h=U?N{{DB4UPn<>qt#6Mw zlTjiXf38tim<0_i0|2gV&a_FB=DgR|+)z~^;;LpV1Mfe`v}`hYkQG6jYiHv;!@aEq z`6?#Q)qiUJ^>#rDVMn{o_FG+(N(k@i5-zipy|UmvS;$6~R=#ua+U{k{YimAT!iwZC zJNp$76W%}k4VKLE(`@Jcp&TQyRY~Ui6P%d+G$!|}EW#%P=&by(L1ajP3$J2IrJlWf z0AsI)8UkJ)lbSsYKn1Dhnx;7(3iw?r3inBCnv)(Q7DTz;*n-WYaK}v{K(KbSUaN0~ z$%L3htebVS6+(E6xxoM}2HuiFf%1>$=jRsw=oGvjod>U=w?Pm#+&amCRaSnv-<^|q zBQAe6dJD!=tv9DKiCwBWS6EYC*b`pa{k)%At7?d;E{)_=msZMH*DCPvvb*)!q_(#< zwTfkDw_m@;Z?yHESzgEq1qx|vWx<<&6tIeZ9fj29=jOtn+@sFG+s^5nb)X+iY7mZh zN6V-2!Umh|az4|)S8{fi6YaGg1iB(vmXwnvBr+31jloFgWD~v$`vCx}*Xe*jwFZ-F zBq2S1aV`TaOW9dxoq@N*yR)3Pt=*G9!q(QtEu-U7K0{LRxmj|j&^>j!T#QN%yr=U~ z@1anj&3noTeC1QDlgK10f6_oqbwN`IA**w#k8@uuto{i*ZRd|A*@xGEu1yplTT5Nz zb3Ay<@+n+N9VI+ApMkfK3vF%|sf@A_PQcqfo|`&(7x1?7a~uA*jpw{=KjzaUoh<&z z(e~N|gl_q%lP6DMRd%Yln3b4w8JxV5vJw#iegVF(OmGNZy#c!}lW`>!f5DoEI&qm5 zV@+^UY-ROgPHW=DRQYH|e(_0hd`}f0*=v&-CLVtjv(98DR%fZH zsja_;!qukcmNstQp*Mc6OFQGda^Sq;b*Rc&c>U$7wc=pd8tXXS7rkd5&lM;O{ZQ~e zGXE%mmB5v&v;*_WW9>Vnj~%l7sJYpdv-!?TFL}XPNeCr1 z;pV##^o+MNa7mN2Cl`O4td^5vW?=>u4)DD7$N!<>O~)uLEiFB5=U(^)g2_8~X1px7 zGk3?}oEPl?~Z?6G#b5Dwr z3zVOc3()me;F5T5UCd9*#kG0~9Y1+8|8NW*U-|Rs8-Cw58bp5_N8Y3u7_#`-nUVHVq2!4J=QMFY^*#bZhN zHH(qh+JrV3GnSsWJrM5WSU=H97Y&_CM3k`6_9-m!neKzVyoQWklAeK6disH*6TQ5= zddXznXC6)CQA=S7(2KMu=@bdC_LQXR9=I2UxHb8VUVE6V>G5Ye;Gs-T{eo-lZkwQ89#<`5N zT+|sZ5bD7J_EJtk#07&iFFD!-bAm{-AsyU=ubDBB%K## zs)%3tj^>*UjqRR)`rCmPq@<(+*nj|Xd0@|;J>R@64R0Ftj^mS^`g?=+~XT(Gt#niMU`KepC!asx!6i{2^g9D z)d~yIwyLeIzXJOK;PNc3M0>&0)*-S)8=V~>fLC}G#Ls_A(>RkKD;GM)`MK%Y+4y*X zgcoeoRAa5QE~~Uy>skct+HPbp7-bjERFiNk z6dX$93zYE%uj!^-TuHDBvsdfu$raiNU*+_$PLh+LD;Iw+8eaQ*MWzcXrrANn^H1}$ z>@rEfTjm73?rS?bMRwo?7qzYFN^MOYE(8JXwF6lUFlA!xH3Hpy3D~mJ(@HKmvho5s z_ZZ@vkwuT<2n6wsV&kh^-9)4W;+JVmZv!4GiS_OH1zzcssfP-cALyE8vw+63roi@TOyc<%ob+HsbO( z8GK%msL}hQXBl{9lWdMu?Oh1(?eu*tPJSHVIK1ge|4KUB8R(Mu{+xfcCkc!1eTUcI z|AB{BrkpDQ@6ilwEWpxf0^Yt?f6mC|;L1*#I)1#ckPWYW>$Ta|+8fKbb9g~}ZC_G4 zO=J4<{tm;NwCBLN8=ZtMI{V{5@USl_O~~*4hu8C-(R;`6ijoB3{U%!gEYDfb67b4K z+&Irl(>e}-Ej|tfexrXx?c;2CrTgd*Uei4MyAa;Xdsy&h&6GO?Z+cqNzRn34c=-OD zwGXx*A2fKC?)JmG&Iv8<9A23Reh*-7Ltz%AH5ZePLSah5+iTXXvl)dY2w1@sgR-*Y zh38&=ggu$pW`|vc;_l#;Y;FAa$A2+amvnrL%mH`-x_i>jb~b;yG`@TI_;xY8a=VzU zRoNNE>gedK9tUUORS4GcvWdWZ92W%?9%tzs39qczja%n(3u#(8le|j`OD|qDsl{~Aq_LFRQaqTreyy@v6U^shYcITsuDnEd4257ov(A|;`2E347 zsq<)?JFTNr;gx?o?Yt-vP273OU;$3TggJpckZE{jeP-RhSXfw6R!%HRKrgOQR#IGc z@y6|0y|{2p6FDs~KT74uMU#Ygt-sU+|K{vH3?>JD94M3QDuY|XX4;LZ9$kViiSNa9 zgzp0duS_*f*bKaN5!Prg_gyqX&m!d#yVb-mC-E@bR9c(^sc@ zb}71OrY6LfN_n8+RZQ}CNNb7pJKXJVNUks7z1Dx;b_yyDd6IB8rvD^jb!-p+PLT)g zXm<8$EpCY&Ph5$_7iZfMXGxsCBUjzN@t;c<&z}SO>1P1$t=p^c=%NHG?nElvTyJL7 zN-@pe5vvq-mOWE?P7~PH-0|-6M`xrn3*dX}eEPn$ zEXaQ^1+R?y_A@&o&z#)uhUAgR9o!CW>ft?UuK!v>bEl2>cBj6>NUrP@F(0L}bCkI2 zfZGYVtd}F=l+&&6$XNhb;tPkt!>o}b`?^UaSh;&oB2J3`wDF$qoISI9(PRp{Yxc=i z9^>iLjy?jOrzif#WMZTrz~)23+y<}>%zA$;yE^-xpi9n^2lyssW0+SpQ3PZwN$=dDokgl0A($I8V_$4O!&OV=#u!ZI-h@$ zamfYm|7+bLyz-ZhrXQu@Eqn|6&6kQ9 zw(7?HL6;cy^mei9f)}GF{+7igyJd+kmgC~brLL@A=Zddp;V%BRzGt(Tg_e$99O^oe zF5Oc-_57eg1BbmQwt`!G`-=m?2G4&#g?sOa@}qQWMq%Odr(9>#rF$vm>T0+?XLXZ^ z@wU`{1YgH~E28|Rl0rJ)t+4DbkGW2#OZQT$j>hWh>Z`HyU%20 zy&XS0OYSq=3;ugM*Un&eff8JN!evrd(EZJQy;IM)Kf2@PKUSus!QiD zlKScA8?N@+11~RMT0I}^J#|}pVJVe|b^)l<;gt=W&61BRwu&gltuk=klTm%uBNQ-Xir66VrF0Pg}XK*H$JQt$$9e7kZdCQ9Bplm`3KcTk_M zf!C#n4PIYZ3HRwk^7E{h7kYH-1Jtu8_~j<+Hsr#E8GX7ThxGL&Uhf88>4pMN;L1Y? zM|2zF>pOZd-?E3ekx}a4Zlis@*y)giy#|9o7L*E%lqiBO3w(S}H&lNXUBX~0&h6th z_%efCgeb+G~I5g&Bj9GcJYgxjsurdx0wc0*$#ZY(`y}0iF*5EG?brq!3(@|X*b9j zG)73$V8TcHP>%WRL|-p*Yw)-fRPkQ$rEbLQJxBYFoO92t1S5ZS#Ak3`Zx6#RtYY6fA{bLI2U+P0{}gj z&RBYZ>%6c^AIyJ+7g(b&e8*t)bo8?e9ER7ekJrSd$m%J0S!JCwd04rZN#QV}``*`^h z2oCACfOv+jCwQX1KxIp$}oR+_HcAEFiXIl`xnHr$@t$W}rS_ zRtYY6f1m0@SJiafuz+}mIvb#ob|Yg2UuHa`4;4Q6(tQkc(7{;m4D|1%J&7@~3w_ul zW8~&b$*v7wVOiV~e7V61c+M)pX?R_O5dSaK6O9d%z(G%&0Xt&{!@r@iW9Z34mR?u@ z_~{1QPlJEaNODhlKpD38eTSfDOF;vQdWTQaQMQn=5Q^>4B4@ODDRV*QE#0dOaMH(sia>a>*r^ nTyn`Jmt1nmC6`>{>Hh!{EkP{^s^Jd+0000&XHvjErn=ru=+&H@H#6 q`};~41=R-|d326HQD}%|W(c{ delta 152 zcmV;J0B8TH0jL3x7=H)`0001~tal~=003`EL_t(|oVCy~3c^qnM9~vbu@(_Qu(tpE zU&5@w4OnX+g2lIq@D;%{nQ9(fE|2MIt)^x%nVc0~zDp@(g$qt!%pHd$Lu-EGjN5p3 zc;J|1fUaGmlmZ)EvBo}0|MTZ0M%xZs^o``x{4euO_X4M09}%XO-LG5#0000 diff --git a/dist/images/markitup/preview.png b/dist/images/markitup/preview.png index b402749728189c62ca4e95a8911624181abf7a59..51ae6c3e6f3ec1916e8e714dab3ac10a62961106 100755 GIT binary patch delta 81 zcmeBRy2La=#hsN&PHmY;&T9PDj3TE delta 9 Qcmcb_)WI}CWn$hF01^@d_5c6? diff --git a/dist/images/markitup/preview_ico.png b/dist/images/markitup/preview_ico.png index 4b707ffa62cf1fcc786d269367dde6817fdaf7e1..f6e036d434c70283f8f63c876efc0f3a03c3244a 100644 GIT binary patch delta 83 zcmdnV)XY3V*@JeqoM>O0Dff{00000 delta 10 RcmZo>-pMpUd1I~^BLEX%11bOj diff --git a/dist/images/markitup/quotes.png b/dist/images/markitup/quotes.png index 947a4a4086b5da9a2ecf562b857966501610caf4..55620b630b6a01303b03b91b6fff49d374bb0920 100644 GIT binary patch delta 82 zcmZ3>^qpyfiaSfOlV=DA2M0$DM@k0+0|RG)M`SSr1MhVZW^~e+UBSS>AX(xXQ4*Y= jR#Ki=l*&+EUaps!mtCBkSdglhUz9%kosHB+MIJ@~oGKVw delta 10 Rcmey)w3cat%EmlSMgSLW1BL(q diff --git a/dist/images/markitup/stroke.png b/dist/images/markitup/stroke.png index 81d446be83ef6d4b5dd96afc58443d58a7fcdfb6..0590cb1dd2635d2b46e80f71cd6ee81c04237017 100644 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUxIQX%vQzP=-q@!%k=d#Wzp$P!n3{h?X delta 252 zcmVI7zWp1=K?I< zfM8)`X(cX1T!CO`AzBI3xDP7}ZER&M>=cAS1Y`3+8Smp2gBVDaf6nD3xv46P#L`0D ze`IUD1=g^IS8U_6NmkXb#0z#?wRQRIo539plZ^YkH!UPN z!U)gU!$Xn@K7L@csyc28;2ptzm#f&vI?gfenD0l24k^h9*Ql!6nXeDtK~>E#!Db)O z+QJz&u-rA?;Ht^?2wdW+^E<^U#w~Vm21D`xpXm#8+Lnj#R3XIx0000

+

@@ -118,6 +119,16 @@ +
-
+

Loading...

- - + + + \ No newline at end of file diff --git a/dist/js/app-loader.js b/dist/js/app-loader.js index b32d718..8027d66 100644 --- a/dist/js/app-loader.js +++ b/dist/js/app-loader.js @@ -1,7 +1,7 @@ (function() { var promise, version; - version = 1422000753297; + version = 1422340547125; window.taigaConfig = { "api": "http://localhost:8000/api/v1/", diff --git a/dist/js/app.js b/dist/js/app.js index 202791a..3953a28 100644 --- a/dist/js/app.js +++ b/dist/js/app.js @@ -1,17 +1,17 @@ -(function(){var configure,init,module,modules,taiga;this.taiga=taiga={},this.taigaContribPlugins=this.taigaContribPlugins||[],taiga.generateHash=function(components){return null==components&&(components=[]),components=_.map(components,function(x){return JSON.stringify(x)}),hex_sha1(components.join(":"))},taiga.generateUniqueSessionIdentifier=function(){var date,randomNumber;return date=(new Date).getTime(),randomNumber=Math.floor(150994944*Math.random()),taiga.generateHash([date,randomNumber])},taiga.sessionId=taiga.generateUniqueSessionIdentifier(),configure=function($routeProvider,$locationProvider,$httpProvider,$provide,$tgEventsProvider,tgLoaderProvider){var authHttpIntercept,defaultHeaders,versionCheckHttpIntercept;return $routeProvider.when("/",{templateUrl:"/partials/projects.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/",{templateUrl:"/partials/project.html"}),$routeProvider.when("/project/:pslug/backlog",{templateUrl:"/partials/backlog.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/taskboard/:sslug",{templateUrl:"/partials/taskboard.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/search",{templateUrl:"/partials/search.html",reloadOnSearch:!1}),$routeProvider.when("/project/:pslug/kanban",{templateUrl:"/partials/kanban.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/us/:usref",{templateUrl:"/partials/us-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/task/:taskref",{templateUrl:"/partials/task-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/wiki",{redirectTo:function(params){return"/project/"+params.pslug+"/wiki/home"}}),$routeProvider.when("/project/:pslug/wiki/:slug",{templateUrl:"/partials/wiki.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/team",{templateUrl:"/partials/views/team/team.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/issues",{templateUrl:"/partials/issues.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/issue/:issueref",{templateUrl:"/partials/issues-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/admin/project-profile/details",{templateUrl:"/partials/admin-project-profile.html"}),$routeProvider.when("/project/:pslug/admin/project-profile/default-values",{templateUrl:"/partials/admin-project-default-values.html"}),$routeProvider.when("/project/:pslug/admin/project-profile/modules",{templateUrl:"/partials/admin-project-modules.html"}),$routeProvider.when("/project/:pslug/admin/project-values/us-status",{templateUrl:"/partials/admin-project-values-us-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/us-points",{templateUrl:"/partials/admin-project-values-us-points.html"}),$routeProvider.when("/project/:pslug/admin/project-values/task-status",{templateUrl:"/partials/admin-project-values-task-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-status",{templateUrl:"/partials/admin-project-values-issue-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-types",{templateUrl:"/partials/admin-project-values-issue-types.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-priorities",{templateUrl:"/partials/admin-project-values-issue-priorities.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-severities",{templateUrl:"/partials/admin-project-values-issue-severities.html"}),$routeProvider.when("/project/:pslug/admin/memberships",{templateUrl:"/partials/admin-memberships.html"}),$routeProvider.when("/project/:pslug/admin/roles",{templateUrl:"/partials/admin-roles.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/github",{templateUrl:"/partials/admin-third-parties-github.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/gitlab",{templateUrl:"/partials/admin-third-parties-gitlab.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/bitbucket",{templateUrl:"/partials/admin-third-parties-bitbucket.html"}),$routeProvider.when("/project/:pslug/admin/contrib/:plugin",{templateUrl:"/partials/contrib/main.html"}),$routeProvider.when("/project/:pslug/user-settings/user-profile",{templateUrl:"/partials/user-profile.html"}),$routeProvider.when("/project/:pslug/user-settings/user-change-password",{templateUrl:"/partials/user-change-password.html"}),$routeProvider.when("/project/:pslug/user-settings/user-avatar",{templateUrl:"/partials/user-avatar.html"}),$routeProvider.when("/project/:pslug/user-settings/mail-notifications",{templateUrl:"/partials/mail-notifications.html"}),$routeProvider.when("/change-email/:email_token",{templateUrl:"/partials/change-email.html"}),$routeProvider.when("/cancel-account/:cancel_token",{templateUrl:"/partials/cancel-account.html"}),$routeProvider.when("/login",{templateUrl:"/partials/login.html"}),$routeProvider.when("/register",{templateUrl:"/partials/register.html"}),$routeProvider.when("/forgot-password",{templateUrl:"/partials/forgot-password.html"}),$routeProvider.when("/change-password",{templateUrl:"/partials/change-password-from-recovery.html"}),$routeProvider.when("/change-password/:token",{templateUrl:"/partials/change-password-from-recovery.html"}),$routeProvider.when("/invitation/:token",{templateUrl:"/partials/invitation.html"}),$routeProvider.when("/error",{templateUrl:"/partials/error.html"}),$routeProvider.when("/not-found",{templateUrl:"/partials/not-found.html"}),$routeProvider.when("/permission-denied",{templateUrl:"/partials/permission-denied.html"}),$routeProvider.otherwise({redirectTo:"/not-found"}),$locationProvider.html5Mode({enabled:!0,requireBase:!1}),defaultHeaders={"Content-Type":"application/json","Accept-Language":"en","X-Session-Id":taiga.sessionId},$httpProvider.defaults.headers["delete"]=defaultHeaders,$httpProvider.defaults.headers.patch=defaultHeaders,$httpProvider.defaults.headers.post=defaultHeaders,$httpProvider.defaults.headers.put=defaultHeaders,$httpProvider.defaults.headers.get={"X-Session-Id":taiga.sessionId},$tgEventsProvider.setSessionId(taiga.sessionId),authHttpIntercept=function($q,$location,$navUrls,$lightboxService){var httpResponseError;return httpResponseError=function(response){var nextPath;return 0===response.status?($lightboxService.closeAll(),$location.path($navUrls.resolve("error")),$location.replace()):401===response.status&&(nextPath=$location.path(),$location.url($navUrls.resolve("login")).search("next="+nextPath)),$q.reject(response)},{responseError:httpResponseError}},$provide.factory("authHttpIntercept",["$q","$location","$tgNavUrls","lightboxService",authHttpIntercept]),$httpProvider.interceptors.push("authHttpIntercept"),versionCheckHttpIntercept=function($q,$confirm){var httpResponseError,versionErrorMsg;return versionErrorMsg="Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost).",httpResponseError=function(response){return 400===response.status&&response.data.version?($confirm.notify("error",versionErrorMsg,null,1e4),$q.reject(response)):$q.reject(response)},{responseError:httpResponseError}},$provide.factory("versionCheckHttpIntercept",["$q","$tgConfirm",versionCheckHttpIntercept]),$httpProvider.interceptors.push("versionCheckHttpIntercept"),window.checksley.updateValidators({linewidth:function(val,width){var lines,valid;return lines=taiga.nl2br(val).split("
"),valid=_.every(lines,function(line){return line.lengthi;i++)if(i in this&&this[i]===item)return i;return-1},__slice=[].slice,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};nl2br=function(){return function(str){var breakTag;return breakTag="
",(str+"").replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g,"$1"+breakTag+"$2")}}(this),bindMethods=function(){return function(object){var dependencies,methods;return dependencies=_.keys(object),methods=[],_.forIn(object,function(value,key){return __indexOf.call(dependencies,key)<0?methods.push(key):void 0}),_.bindAll(object,methods)}}(this),bindOnce=function(){return function(scope,attr,continuation){var delBind,val;return val=scope.$eval(attr),void 0!==val?continuation(val):(delBind=null,delBind=scope.$watch(attr,function(val){return void 0!==val?(continuation(val),delBind?delBind():void 0):void 0}))}}(this),mixOf=function(){var Mixed,base,method,mixin,mixins,name,_i,_ref;for(base=arguments[0],mixins=2<=arguments.length?__slice.call(arguments,1):[],Mixed=function(_super){function Mixed(){return Mixed.__super__.constructor.apply(this,arguments)}return __extends(Mixed,_super),Mixed}(base),_i=mixins.length-1;_i>=0;_i+=-1){mixin=mixins[_i],_ref=mixin.prototype;for(name in _ref)method=_ref[name],Mixed.prototype[name]=method}return Mixed},trim=function(data,char){return _.str.trim(data,char)},slugify=function(data){return _.str.slugify(data)},unslugify=function(data){return data?_.str.capitalize(data.replace(/-/g," ")):data},toggleText=function(element,texts){var nextTextPosition,text;return nextTextPosition=element.data("nextTextPosition"),(null==nextTextPosition||nextTextPosition>=texts.length)&&(nextTextPosition=0),text=texts[nextTextPosition],element.data("nextTextPosition",nextTextPosition+1),element.text(text)},groupBy=function(coll,pred){var item,result,_i,_len;for(result={},_i=0,_len=coll.length;_len>_i;_i++)item=coll[_i],result[pred(item)]=item;return result},timeout=function(wait,continuation){return window.setTimeout(continuation,wait)},cancelTimeout=function(timeoutVar){return window.clearTimeout(timeoutVar)},scopeDefer=function(scope,func){return _.defer(function(){return function(){return scope.$apply(func)}}(this))},toString=function(value){return _.isNumber(value)?value+"":_.isString(value)?value:_.isPlainObject(value)?JSON.stringify(value):_.isUndefined(value)?"":value.toString()},joinStr=function(str,coll){return _.str.join(str,coll)},debounce=function(wait,func){return _.debounce(func,wait,{leading:!0,trailing:!1})},debounceLeading=function(wait,func){return _.debounce(func,wait,{leading:!1,trailing:!0})},startswith=function(str1,str2){return _.str.startsWith(str1,str2)},sizeFormat=function(input,precision){var number,size,units;return null==precision&&(precision=1),isNaN(parseFloat(input))||!isFinite(input)?"-":0===input?"0 bytes":(units=["bytes","KB","MB","GB","TB","PB"],number=Math.floor(Math.log(input)/Math.log(1024)),number>5&&(number=5),size=(input/Math.pow(1024,number)).toFixed(precision),""+size+" "+units[number])},taiga=this.taiga,taiga.nl2br=nl2br,taiga.bindMethods=bindMethods,taiga.bindOnce=bindOnce,taiga.mixOf=mixOf,taiga.trim=trim,taiga.slugify=slugify,taiga.unslugify=unslugify,taiga.toggleText=toggleText,taiga.groupBy=groupBy,taiga.timeout=timeout,taiga.cancelTimeout=cancelTimeout,taiga.scopeDefer=scopeDefer,taiga.toString=toString,taiga.joinStr=joinStr,taiga.debounce=debounce,taiga.debounceLeading=debounceLeading,taiga.startswith=startswith,taiga.sizeFormat=sizeFormat}.call(this),function(){var FiltersMixin,PageMixin,groupBy,joinStr,taiga,toString,trim;taiga=this.taiga,groupBy=this.taiga.groupBy,joinStr=this.taiga.joinStr,trim=this.taiga.trim,toString=this.taiga.toString,PageMixin=function(){function PageMixin(){}return PageMixin.prototype.fillUsersAndRoles=function(users,roles){var activeUsers,availableRoles;return activeUsers=_.filter(users,function(){return function(user){return user.is_active}}(this)),this.scope.activeUsers=_.sortBy(activeUsers,"full_name_display"),this.scope.activeUsersById=groupBy(this.scope.activeUsers,function(e){return e.id}),this.scope.users=_.sortBy(users,"full_name_display"),this.scope.usersById=groupBy(this.scope.users,function(e){return e.id}),this.scope.roles=_.sortBy(roles,"order"),availableRoles=_(this.scope.project.memberships).map("role").uniq().value(),this.scope.computableRoles=_(roles).filter("computable").filter(function(x){return _.contains(availableRoles,x.id)}).value()},PageMixin.prototype.loadUsersAndRoles=function(){var promise;return promise=this.q.all([this.rs.projects.usersList(this.scope.projectId),this.rs.projects.rolesList(this.scope.projectId)]),promise.then(function(_this){return function(results){var roles,users;return users=results[0],roles=results[1],_this.fillUsersAndRoles(users,roles),results}}(this))},PageMixin}(),taiga.PageMixin=PageMixin,FiltersMixin=function(){function FiltersMixin(){}return FiltersMixin.prototype.selectFilter=function(name,value,load){var existing,location,params;return null==load&&(load=!1),params=this.location.search(),void 0!==params[name]&&"page"!==name&&(existing=_.map(taiga.toString(params[name]).split(","),function(x){return trim(x)}),existing.push(taiga.toString(value)),existing=_.compact(existing),value=joinStr(",",_.uniq(existing))),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)},FiltersMixin.prototype.replaceFilter=function(name,value,load){var location;return null==load&&(load=!1),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)},FiltersMixin.prototype.replaceAllFilters=function(filters,load){var location;return null==load&&(load=!1),location=load?this.location:this.location.noreload(this.scope),location.search(filters)},FiltersMixin.prototype.unselectFilter=function(name,value,load){var location,newValues,params,parsedValues;return null==load&&(load=!1),params=this.location.search(),void 0!==params[name]?((void 0===value||null===value)&&delete params[name],parsedValues=_.map(taiga.toString(params[name]).split(","),function(x){return trim(x)}),newValues=_.reject(parsedValues,function(x){return x===taiga.toString(value)}),newValues=_.compact(newValues),value=_.isEmpty(newValues)?null:joinStr(",",_.uniq(newValues)),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)):void 0},FiltersMixin}(),taiga.FiltersMixin=FiltersMixin}.call(this),function(){var module;module=angular.module("taigaAdmin",[])}.call(this),function(){var AuthService,CancelAccountDirective,ChangeEmailDirective,ChangePasswordFromRecoveryDirective,ForgotPasswordDirective,InvitationDirective,LoginDirective,PublicRegisterMessageDirective,RegisterDirective,debounce,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,debounce=this.taiga.debounce,module=angular.module("taigaAuth",["taigaResources"]),AuthService=function(_super){function AuthService(rootscope,storage,model,rs,http,urls){this.rootscope=rootscope,this.storage=storage,this.model=model,this.rs=rs,this.http=http,this.urls=urls,AuthService.__super__.constructor.call(this)}return __extends(AuthService,_super),AuthService.$inject=["$rootScope","$tgStorage","$tgModel","$tgResources","$tgHttp","$tgUrls"],AuthService.prototype.getUser=function(){var user,userData;return this.rootscope.user?this.rootscope.user:(userData=this.storage.get("userInfo"),userData?(user=this.model.make_model("users",userData),this.rootscope.user=user,user):null)},AuthService.prototype.setUser=function(user){return this.rootscope.auth=user,this.rootscope.$broadcast("i18n:change",user.default_language),this.storage.set("userInfo",user.getAttrs()),this.rootscope.user=user},AuthService.prototype.clear=function(){return this.rootscope.auth=null,this.rootscope.user=null,this.storage.remove("userInfo")},AuthService.prototype.setToken=function(token){return this.storage.set("token",token)},AuthService.prototype.getToken=function(){return this.storage.get("token")},AuthService.prototype.removeToken=function(){return this.storage.remove("token")},AuthService.prototype.isAuthenticated=function(){return null!==this.getUser()?!0:!1},AuthService.prototype.login=function(data,type){var url;return url=this.urls.resolve("auth"),data=_.clone(data,!1),data.type=type?type:"normal",this.removeToken(),this.http.post(url,data).then(function(_this){return function(data){var user;return user=_this.model.make_model("users",data.data),_this.setToken(user.auth_token),_this.setUser(user),user}}(this))},AuthService.prototype.logout=function(){return this.removeToken(),this.clear()},AuthService.prototype.register=function(data,type,existing){var url;return url=this.urls.resolve("auth-register"),data=_.clone(data,!1),data.type=type?type:"public","private"===type&&(data.existing=existing?existing:!1),this.removeToken(),this.http.post(url,data).then(function(_this){return function(response){var user;return user=_this.model.make_model("users",response.data),_this.setToken(user.auth_token),_this.setUser(user),user}}(this))},AuthService.prototype.getInvitation=function(token){return this.rs.invitations.get(token)},AuthService.prototype.acceptInvitiationWithNewUser=function(data){return this.register(data,"private",!1)},AuthService.prototype.acceptInvitiationWithExistingUser=function(data){return this.register(data,"private",!0)},AuthService.prototype.forgotPassword=function(data){var url;return url=this.urls.resolve("users-password-recovery"),data=_.clone(data,!1),this.removeToken(),this.http.post(url,data)},AuthService.prototype.changePasswordFromRecovery=function(data){var url;return url=this.urls.resolve("users-change-password-from-recovery"),data=_.clone(data,!1),this.removeToken(),this.http.post(url,data)},AuthService.prototype.changeEmail=function(data){var url;return url=this.urls.resolve("users-change-email"),data=_.clone(data,!1),this.http.post(url,data)},AuthService.prototype.cancelAccount=function(data){var url;return url=this.urls.resolve("users-cancel-account"),data=_.clone(data,!1),this.http.post(url,data)},AuthService}(taiga.Service),module.service("$tgAuth",AuthService),PublicRegisterMessageDirective=function($config,$navUrls){var template,templateFn;return template=_.template(''),templateFn=function(){var publicRegisterEnabled;return publicRegisterEnabled=$config.get("publicRegisterEnabled"),publicRegisterEnabled?template({url:$navUrls.resolve("register")}):""},{restrict:"AE",scope:{},template:templateFn}},module.directive("tgPublicRegisterMessage",["$tgConfig","$tgNavUrls",PublicRegisterMessageDirective]),LoginDirective=function($auth,$confirm,$location,$config,$routeParams,$navUrls,$events){var link;return link=function($scope,$el){var onError,onSuccess,submit;return onSuccess=function(){var nextUrl;return nextUrl=$routeParams.next&&$routeParams.next!==$navUrls.resolve("login")?$routeParams.next:$navUrls.resolve("home"),$events.setupConnection(),$location.path(nextUrl)},onError=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your username/email or password are incorrect.")},submit=debounce(2e3,function(){return function(event){var data,form,promise;return event.preventDefault(),form=new checksley.Form($el.find("form.login-form")),form.validate()?(data={username:$el.find("form.login-form input[name=username]").val(),password:$el.find("form.login-form input[name=password]").val()},promise=$auth.login(data),promise.then(onSuccess,onError)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLogin",["$tgAuth","$tgConfirm","$tgLocation","$tgConfig","$routeParams","$tgNavUrls","$tgEvents",LoginDirective]),RegisterDirective=function($auth,$confirm,$location,$navUrls,$config,$analytics){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $config.get("publicRegisterEnabled")||($location.path($navUrls.resolve("not-found")),$location.replace()),$scope.data={},form=$el.find("form").checksley({onlyOneErrorElement:!0}),onSuccessSubmit=function(){return $analytics.trackEvent("auth","register","user registration",1),$confirm.notify("success","Our Oompa Loompas are happy, welcome to Taiga."),$location.path($navUrls.resolve("home"))},onErrorSubmit=function(response){return null!=response.data._error_message&&$confirm.notify("light-error","According to our Oompa Loompas there was an error. "+response.data._error_message),form.setErrors(response.data)},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.register($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgRegister",["$tgAuth","$tgConfirm","$tgLocation","$tgNavUrls","$tgConfig","$tgAnalytics",RegisterDirective]),ForgotPasswordDirective=function($auth,$confirm,$location,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},form=$el.find("form").checksley(),onSuccessSubmit=function(response){return $location.path($navUrls.resolve("login")),$confirm.success("Check your inbox!
We have sent a mail to
"+response.data.email+"
with the instructions to set a new password")},onErrorSubmit=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your are not registered yet.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.forgotPassword($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgForgotPassword",["$tgAuth","$tgConfirm","$tgLocation","$tgNavUrls",ForgotPasswordDirective]),ChangePasswordFromRecoveryDirective=function($auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},null!=$params.token?($scope.tokenInParams=!0,$scope.data.token=$params.token):$scope.tokenInParams=!1,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $location.path($navUrls.resolve("login")),$confirm.success("Our Oompa Loompas saved your new password.
Try to sign in with it.")},onErrorSubmit=function(response){return $confirm.notify("light-error","One of our Oompa Loompas say '"+response.data._error_message+"'.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.changePasswordFromRecovery($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgChangePasswordFromRecovery",["$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",ChangePasswordFromRecoveryDirective]),InvitationDirective=function($auth,$confirm,$location,$params,$navUrls,$analytics){var link;return link=function($scope,$el){var loginForm,onErrorSubmitLogin,onErrorSubmitRegister,onSuccessSubmitLogin,onSuccessSubmitRegister,promise,registerForm,submitLogin,submitRegister,token;return token=$params.token,promise=$auth.getInvitation(token),promise.then(function(invitation){return $scope.invitation=invitation}),promise.then(null,function(){return $location.path($navUrls.resolve("login")),$confirm.success("Ooops, we have a problem
Our Oompa Loompas can't find your invitation.")}),$scope.dataLogin={token:token},loginForm=$el.find("form.login-form").checksley({onlyOneErrorElement:!0}),onSuccessSubmitLogin=function(){return $analytics.trackEvent("auth","invitationAccept","invitation accept with existing user",1),$location.path($navUrls.resolve("project",{project:$scope.invitation.project_slug})),$confirm.notify("success","You've successfully joined this project","Welcome to "+_.escape($scope.invitation.project_name))},onErrorSubmitLogin=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your are not registered yet or typed an invalid password.")},submitLogin=debounce(2e3,function(){return function(event){return event.preventDefault(),loginForm.validate()?(promise=$auth.acceptInvitiationWithExistingUser($scope.dataLogin),promise.then(onSuccessSubmitLogin,onErrorSubmitLogin)):void 0}}(this)),$el.on("submit","form.login-form",submitLogin),$el.on("click",".button-login",submitLogin),$scope.dataRegister={token:token},registerForm=$el.find("form.register-form").checksley(),onSuccessSubmitRegister=function(){return $analytics.trackEvent("auth","invitationAccept","invitation accept with new user",1),$location.path($navUrls.resolve("project",{project:$scope.invitation.project_slug})),$confirm.notify("success","You've successfully joined this project","Welcome to "+_.escape($scope.invitation.project_name))},onErrorSubmitRegister=function(){return $confirm.notify("light-error","According to our Oompa Loompas, that username or email is already in use.")},submitRegister=debounce(2e3,function(){return function(event){return event.preventDefault(),registerForm.validate()?(promise=$auth.acceptInvitiationWithNewUser($scope.dataRegister),promise.then(onSuccessSubmitRegister,onErrorSubmitRegister)):void 0}}(this)),$el.on("submit","form.register-form",submitRegister),$el.on("click",".button-register",submitRegister)},{link:link}},module.directive("tgInvitation",["$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls","$tgAnalytics",InvitationDirective]),ChangeEmailDirective=function($repo,$model,$auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},$scope.data.email_token=$params.email_token,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $repo.queryOne("users",$auth.getUser().id).then(function(){return function(data){return $auth.setUser(data),$location.path($navUrls.resolve("home")),$confirm.success("Our Oompa Loompas updated your email")}}(this))},onErrorSubmit=function(response){return $confirm.notify("error","One of our Oompa Loompas says '"+response.data._error_message+"'.")},submit=function(){var promise;if(form.validate())return promise=$auth.changeEmail($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)},$el.on("submit",function(event){return event.preventDefault(),submit()}),$el.on("click","a.button-change-email",function(event){return event.preventDefault(),submit()})},{link:link}},module.directive("tgChangeEmail",["$tgRepo","$tgModel","$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",ChangeEmailDirective]),CancelAccountDirective=function($repo,$model,$auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},$scope.data.cancel_token=$params.cancel_token,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $auth.logout(),$location.path($navUrls.resolve("home")),$confirm.success("Our Oompa Loompas removed your account")},onErrorSubmit=function(response){return $confirm.notify("error","One of our Oompa Loompas says '"+response.data._error_message+"'.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.cancelAccount($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgCancelAccount",["$tgRepo","$tgModel","$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",CancelAccountDirective])}.call(this),function(){var module;module=angular.module("taigaBacklog",[])}.call(this),function(){var TaigaMainDirective,bindOnce,groupBy,init,module,taiga,urls;taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaBase",["taigaLocales"]),TaigaMainDirective=function($rootscope,$window){var link;return link=function(){return $window.onresize=function(){return $rootscope.$broadcast("resize")}},{link:link}},module.directive("tgMain",["$rootScope","$window",TaigaMainDirective]),urls={home:"/",error:"/error","not-found":"/not-found","permission-denied":"/permission-denied",login:"/login","forgot-password":"/forgot-password","change-password":"/change-password/:token","change-email":"/change-email/:token","cancel-account":"/cancel-account/:token",register:"/register",invitation:"/invitation/:token","create-project":"/create-project",profile:"/:user",project:"/project/:project","project-backlog":"/project/:project/backlog","project-taskboard":"/project/:project/taskboard/:sprint","project-kanban":"/project/:project/kanban","project-issues":"/project/:project/issues","project-search":"/project/:project/search","project-userstories-detail":"/project/:project/us/:ref","project-tasks-detail":"/project/:project/task/:ref","project-issues-detail":"/project/:project/issue/:ref","project-wiki":"/project/:project/wiki","project-wiki-page":"/project/:project/wiki/:slug","project-team":"/project/:project/team","project-admin-home":"/project/:project/admin/project-profile/details","project-admin-project-profile-details":"/project/:project/admin/project-profile/details","project-admin-project-profile-default-values":"/project/:project/admin/project-profile/default-values","project-admin-project-profile-modules":"/project/:project/admin/project-profile/modules","project-admin-project-values-us-status":"/project/:project/admin/project-values/us-status","project-admin-project-values-us-points":"/project/:project/admin/project-values/us-points","project-admin-project-values-task-status":"/project/:project/admin/project-values/task-status","project-admin-project-values-issue-status":"/project/:project/admin/project-values/issue-status","project-admin-project-values-issue-types":"/project/:project/admin/project-values/issue-types","project-admin-project-values-issue-priorities":"/project/:project/admin/project-values/issue-priorities","project-admin-project-values-issue-severities":"/project/:project/admin/project-values/issue-severities","project-admin-memberships":"/project/:project/admin/memberships","project-admin-roles":"/project/:project/admin/roles","project-admin-third-parties-github":"/project/:project/admin/third-parties/github","project-admin-third-parties-gitlab":"/project/:project/admin/third-parties/gitlab","project-admin-third-parties-bitbucket":"/project/:project/admin/third-parties/bitbucket","project-admin-contrib":"/project/:project/admin/contrib/:plugin","user-settings-user-profile":"/project/:project/user-settings/user-profile","user-settings-user-change-password":"/project/:project/user-settings/user-change-password","user-settings-user-avatar":"/project/:project/user-settings/user-avatar","user-settings-mail-notifications":"/project/:project/user-settings/mail-notifications"},init=function($log,$navurls){return $log.debug("Initialize navigation urls"),$navurls.update(urls) -},module.run(["$log","$tgNavUrls",init])}.call(this),function(){var AnimationFrame,AppTitle,CheckPermissionDirective,LimitLineLengthDirective,ProjectUrl,Qqueue,SelectedText,ToggleCommentDirective,module,taiga,__slice=[].slice;taiga=this.taiga,module=angular.module("taigaCommon",[]),SelectedText=function($window,$document){var get;return get=function(){return $window.getSelection?$window.getSelection().toString():$document.selection?$document.selection.createRange().text:""},{get:get}},module.factory("$selectedText",["$window","$document",SelectedText]),CheckPermissionDirective=function(){var link,render;return render=function($el,project,permission){return project.my_permissions.indexOf(permission)>-1?$el.removeClass("hidden"):void 0},link=function($scope,$el,$attrs){var permission;return $el.addClass("hidden"),permission=$attrs.tgCheckPermission,$scope.$watch("project",function(project){return null!=project?render($el,project,permission):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgCheckPermission",CheckPermissionDirective),AnimationFrame=function(){var add,animationFrame,performAnimation,tail;return animationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame,performAnimation=function(){return function(){var fn;return fn=tail.shift(),fn(),tail.length?animationFrame(performAnimation):void 0}}(this),tail=[],add=function(){var fn,_i,_len,_results;for(_results=[],_i=0,_len=arguments.length;_len>_i;_i++)fn=arguments[_i],tail.push(fn),_results.push(1===tail.length?animationFrame(performAnimation):void 0);return _results},{add:add}},module.factory("animationFrame",AnimationFrame),ToggleCommentDirective=function(){var link;return link=function($scope,$el){return $el.find("textarea").on("focus",function(){return $el.addClass("active")})},{link:link}},module.directive("tgToggleComment",ToggleCommentDirective),AppTitle=function(){var set;return set=function(text){return $("title").text(text)},{set:set}},module.factory("$appTitle",AppTitle),ProjectUrl=function($navurls){var get;return get=function(project){var ctx;return ctx={project:project.slug},project.is_backlog_activated&&project.my_permissions.indexOf("view_us")>-1?$navurls.resolve("project-backlog",ctx):project.is_kanban_activated&&project.my_permissions.indexOf("view_us")>-1?$navurls.resolve("project-kanban",ctx):project.is_wiki_activated&&project.my_permissions.indexOf("view_wiki_pages")>-1?$navurls.resolve("project-wiki",ctx):project.is_issues_activated&&project.my_permissions.indexOf("view_issues")>-1?$navurls.resolve("project-issues",ctx):$navurls.resolve("project",ctx)},{get:get}},module.factory("$projectUrl",["$tgNavUrls",ProjectUrl]),LimitLineLengthDirective=function(){var link;return link=function($scope,$el){var maxColsPerLine;return maxColsPerLine=parseInt($el.attr("cols")),$el.on("keyup",function(event){var code,lines;return code=event.keyCode,lines=$el.val().split("\n"),_.each(lines,function(line,index){return lines[index]=line.substring(0,maxColsPerLine-2)}),$el.val(lines.join("\n"))})},{link:link}},module.directive("tgLimitLineLength",LimitLineLengthDirective),Qqueue=function($q){var deferred,lastPromise,qqueue;return deferred=$q.defer(),deferred.resolve(),lastPromise=deferred.promise,qqueue={bindAdd:function(_this){return function(fn){return function(){var args;return args=1<=arguments.length?__slice.call(arguments,0):[],lastPromise=lastPromise.then(function(){return fn.apply(_this,args)})}}}(this),add:function(){return function(fn){return lastPromise=lastPromise?lastPromise.then(fn):fn(),qqueue}}(this)}},module.factory("$tgQqueue",["$q",Qqueue])}.call(this),function(){var EventsProvider,EventsService,bindMethods,module,startswith,taiga;taiga=this.taiga,startswith=this.taiga.startswith,bindMethods=this.taiga.bindMethods,module=angular.module("taigaEvents",[]),EventsService=function(){function EventsService(win,log,config,auth){this.win=win,this.log=log,this.config=config,this.auth=auth,bindMethods(this)}return EventsService.prototype.initialize=function(sessionId){return this.sessionId=sessionId,this.subscriptions={},this.connected=!1,this.error=!1,this.pendingMessages=[],void 0===this.win.WebSocket?this.log.info("WebSockets not supported on your browser"):void 0},EventsService.prototype.setupConnection=function(){var loc,path,scheme,url;return this.stopExistingConnection(),(url=this.config.get("eventsUrl"))?(startswith(url,"ws:")||startswith(url,"wss:")||(loc=this.win.location,scheme="https:"===loc.protocol?"wss:":"ws:",path=_.str.ltrim(url,"/"),url=""+scheme+"//"+loc.host+"/"+path),this.ws=new this.win.WebSocket(url),this.ws.addEventListener("open",this.onOpen),this.ws.addEventListener("message",this.onMessage),this.ws.addEventListener("error",this.onError),this.ws.addEventListener("close",this.onClose)):void 0},EventsService.prototype.stopExistingConnection=function(){return void 0!==this.ws?(this.ws.removeEventListener("open",this.onOpen),this.ws.removeEventListener("close",this.onClose),this.ws.removeEventListener("error",this.onError),this.ws.removeEventListener("message",this.onMessage),this.ws.close(),delete this.ws):void 0},EventsService.prototype.serialize=function(message){return _.isObject(message)?JSON.stringify(message):message},EventsService.prototype.sendMessage=function(message){var messages,msg,_i,_len,_results;if(this.pendingMessages.push(message),this.connected){for(messages=_.map(this.pendingMessages,this.serialize),this.pendingMessages=[],_results=[],_i=0,_len=messages.length;_len>_i;_i++)msg=messages[_i],_results.push(this.ws.send(msg));return _results}},EventsService.prototype.subscribe=function(scope,routingKey,callback){var message,subscription;if(!this.error)return this.log.debug("Subscribe to: "+routingKey),subscription={scope:scope,routingKey:routingKey,callback:_.debounce(callback,500,{leading:!0,trailing:!1})},message={cmd:"subscribe",routing_key:routingKey},this.subscriptions[routingKey]=subscription,this.sendMessage(message),scope.$on("$destroy",function(_this){return function(){return _this.unsubscribe(routingKey)}}(this))},EventsService.prototype.unsubscribe=function(routingKey){var message;if(!this.error)return this.log.debug("Unsubscribe from: "+routingKey),message={cmd:"unsubscribe",routing_key:routingKey},this.sendMessage(message)},EventsService.prototype.onOpen=function(){var message,token;return this.connected=!0,this.log.debug("WebSocket connection opened"),token=this.auth.getToken(),message={cmd:"auth",data:{token:token,sessionId:this.sessionId}},this.sendMessage(message)},EventsService.prototype.onMessage=function(event){var data,routingKey,subscription;return this.log.debug("WebSocket message received: "+event.data),data=JSON.parse(event.data),routingKey=data.routing_key,null!=this.subscriptions[routingKey]?(subscription=this.subscriptions[routingKey],subscription.scope.$apply(function(){return subscription.callback(data.data)})):void 0},EventsService.prototype.onError=function(error){return this.log.error("WebSocket error: "+error),this.error=!0},EventsService.prototype.onClose=function(){return this.log.debug("WebSocket closed."),this.connected=!1},EventsService}(),EventsProvider=function(){function EventsProvider(){}return EventsProvider.prototype.setSessionId=function(sessionId){return this.sessionId=sessionId},EventsProvider.prototype.$get=function($win,$log,$conf,$auth){var service;return service=new EventsService($win,$log,$conf,$auth),service.initialize(this.sessionId),service},EventsProvider.prototype.$get.$inject=["$window","$log","$tgConfig","$tgAuth"],EventsProvider}(),module.provider("$tgEvents",EventsProvider)}.call(this),function(){var FeedbackDirective,bindOnce,debounce,groupBy,mixOf,module,taiga,trim;taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,mixOf=this.taiga.mixOf,debounce=this.taiga.debounce,trim=this.taiga.trim,module=angular.module("taigaFeedback",[]),FeedbackDirective=function($lightboxService,$repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley(),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("feedback",$scope.feedback),promise.then(function(){return $loading.finish(submitButton),$lightboxService.close($el),$confirm.notify("success","\\o/ we'll be happy to read your")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("feedback:show",function(){return $scope.$apply(function(){return $scope.feedback={}}),$lightboxService.open($el),$el.find("textarea").focus()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbFeedback",["lightboxService","$tgRepo","$tgConfirm","$tgLoading",FeedbackDirective])}.call(this),function(){var module;module=angular.module("taigaIntegrations",[])}.call(this),function(){var module;module=angular.module("taigaIssues",[])}.call(this),function(){var module;module=angular.module("taigaKanban",[])}.call(this),function(){var module;module=angular.module("taigaLocales",[])}.call(this),function(){var ProjectMenuDirective,ProjectsNavigationController,ProjectsNavigationDirective,bindOnce,groupBy,module,taiga,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,module=angular.module("taigaNavMenu",[]),ProjectsNavigationController=function(_super){function ProjectsNavigationController(scope,rootscope,rs,navurls,projectUrl){var promise;this.scope=scope,this.rootscope=rootscope,this.rs=rs,this.navurls=navurls,this.projectUrl=projectUrl,promise=this.loadInitialData(),promise.then(null,function(){return console.log("FAIL")}),this.scope.$on("projects:reload",function(_this){return function(){return _this.loadInitialData()}}(this)),this.scope.$on("project:loaded",function(_this){return function(){return _this.loadInitialData()}}(this))}return __extends(ProjectsNavigationController,_super),ProjectsNavigationController.$inject=["$scope","$rootScope","$tgResources","$tgNavUrls","$projectUrl"],ProjectsNavigationController.prototype.loadInitialData=function(){return this.rs.projects.list().then(function(_this){return function(projects){var project,_i,_len;for(_i=0,_len=projects.length;_len>_i;_i++)project=projects[_i],project.url=_this.projectUrl.get(project);return _this.scope.projects=projects,_this.scope.filteredProjects=projects,_this.scope.filterText="",projects}}(this))},ProjectsNavigationController.prototype.newProject=function(){return this.scope.$apply(function(_this){return function(){return _this.rootscope.$broadcast("projects:create")}}(this))},ProjectsNavigationController.prototype.filterProjects=function(text){return this.scope.filteredProjects=_.filter(this.scope.projects,function(project){return project.name.toLowerCase().indexOf(text)>-1}),this.scope.filterText=text,this.rootscope.$broadcast("projects:filtered")},ProjectsNavigationController}(taiga.Controller),module.controller("ProjectsNavigationController",ProjectsNavigationController),ProjectsNavigationDirective=function($rootscope,animationFrame,$timeout,tgLoader,$location,$compile){var baseTemplate,hideMenu,link,loadingStart,overlay,projectsTemplate;return baseTemplate=_.template('

Your projects

\n
\n
\n \n \n
\n
\n\n\n\n
\n \n
\n
    \n
\n
\n \n
'),projectsTemplate=_.template('<% _.each(projects, function(project) { %>\n
  • \n \n <%- project.name %>\n \n \n
  • \n<% }) %>'),overlay=$(".projects-nav-overlay"),loadingStart=0,hideMenu=function(){var difftime,timeoutValue;return overlay.is(":visible")?(difftime=(new Date).getTime()-loadingStart,timeoutValue=0,1e3>difftime&&(timeoutValue=1e3-timeoutValue),timeout(timeoutValue,function(){return overlay.one("transitionend",function(){return $(document.body).removeClass("loading-project open-projects-nav closed-projects-nav").css("overflow-x","visible"),overlay.hide()}),$(document.body).addClass("closed-projects-nav"),tgLoader.disablePreventLoading()})):void 0},link=function($scope,$el,$attrs,$ctrls){var $ctrl,render,renderProjects;return $ctrl=$ctrls[0],$rootscope.$on("project:loaded",hideMenu),renderProjects=function(projects){var html;return html=projectsTemplate({projects:projects}),$el.find(".projects-list").html(html),$scope.$emit("regenerate:project-pagination")},render=function(projects){return $el.html($compile(baseTemplate())($scope)),renderProjects(projects)},overlay.on("click",function(){return hideMenu()}),$(document).on("keydown",function(){return function(e){var code;return code=e.keyCode?e.keyCode:e.which,27===code?hideMenu():void 0}}(this)),$scope.$on("nav:projects-list:open",function(){return $(document.body).hasClass("open-projects-nav")||animationFrame.add(function(){return function(){return overlay.show()}}(this)),animationFrame.add(function(){return function(){return $(document.body).css("overflow-x","hidden")}}(this),function(){return function(){return $(document.body).toggleClass("open-projects-nav")}}(this))}),$el.on("click",".projects-list > li > a",function(event){var currentUrl,nextUrl,target;return target=angular.element(event.currentTarget),nextUrl=target.prop("href"),currentUrl=$location.absUrl(),nextUrl===currentUrl?void hideMenu():($(document.body).addClass("loading-project"),tgLoader.preventLoading(),loadingStart=(new Date).getTime())}),$el.on("click",".create-project-button .button",function(event){return event.preventDefault(),$ctrl.newProject()}),$el.on("keyup",".search-project",function(event){var target;return target=angular.element(event.currentTarget),$ctrl.filterProjects(target.val())}),$scope.$on("projects:filtered",function(){return renderProjects($scope.filteredProjects)}),$scope.$watch("projects",function(projects){return null!=projects?render(projects):void 0})},{require:["tgProjectsNav"],controller:ProjectsNavigationController,link:link}},module.directive("tgProjectsNav",["$rootScope","animationFrame","$timeout","tgLoader","$tgLocation","$compile",ProjectsNavigationDirective]),ProjectMenuDirective=function($log,$compile,$auth,$rootscope,$tgAuth,$location,$navUrls,$config){var getSectionName,link,mainTemplate,menuEntriesTemplate,renderMainMenu,renderMenuEntries,videoConferenceUrl;return menuEntriesTemplate=_.template(''),mainTemplate=_.template('\n'),getSectionName=function($el,sectionName,project){var oldSectionName,_ref;return oldSectionName=null!=(_ref=$el.find("a.active").parent().attr("id"))?_ref.replace("nav-",""):void 0,"backlog-kanban"===sectionName&&("backlog"===oldSectionName||"kanban"===oldSectionName?sectionName=oldSectionName:project.is_backlog_activated&&!project.is_kanban_activated?sectionName="backlog":!project.is_backlog_activated&&project.is_kanban_activated&&(sectionName="kanban")),sectionName},renderMainMenu=function($el){var html;return html=mainTemplate({}),$el.html(html)},renderMenuEntries=function($el,targetScope,project){var container,ctx,dom,sectionName;return null==project&&(project={}),container=$el.find(".menu-container"),sectionName=getSectionName($el,targetScope.section,project),ctx={user:$auth.getUser(),project:project,feedbackEnabled:$config.get("feedbackEnabled")},dom=$compile(menuEntriesTemplate(ctx))(targetScope),dom.find("a.active").removeClass("active"),dom.find("#nav-"+sectionName+" > a").addClass("active"),container.replaceWith(dom)},videoConferenceUrl=function(project){var baseUrl,url;if("appear-in"===project.videoconferences)baseUrl="https://appear.in/";else{if("talky"!==project.videoconferences)return"";baseUrl="https://talky.io/"}return url=project.videoconferences_salt?""+project.slug+"-"+project.videoconferences_salt:""+project.slug,baseUrl+url},link=function($scope,$el){var project;return renderMainMenu($el),project=null,$el.on("click",".logo",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$rootscope.$broadcast("nav:projects-list:open")}),$el.on("click",".user-settings .avatar",function(event){return event.preventDefault(),$el.find(".user-settings .popover").popover().open()}),$el.on("click",".logout",function(event){return event.preventDefault(),$auth.logout(),$scope.$apply(function(){return $location.path($navUrls.resolve("login"))})}),$el.on("click","#nav-search > a",function(event){return event.preventDefault(),$rootscope.$broadcast("search-box:show",project)}),$el.on("click",".feedback",function(event){return event.preventDefault(),$rootscope.$broadcast("feedback:show")}),$scope.$on("projects:loaded",function(listener){return $el.addClass("hidden"),listener.stopPropagation()}),$scope.$on("project:loaded",function(ctx,newProject){return project=newProject,$el.hasClass("hidden")&&$el.removeClass("hidden"),project.videoconferenceUrl=videoConferenceUrl(project),renderMenuEntries($el,ctx.targetScope,project)})},{link:link}},module.directive("tgProjectMenu",["$log","$compile","$tgAuth","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","$tgConfig",ProjectMenuDirective])}.call(this),function(){var module;module=angular.module("taigaProject",[])}.call(this),function(){var RelatedTaskAssignedToInlineEditionDirective,RelatedTaskCreateButtonDirective,RelatedTaskCreateFormDirective,RelatedTaskRowDirective,RelatedTasksDirective,debounce,module,taiga,trim;taiga=this.taiga,trim=this.taiga.trim,debounce=this.taiga.debounce,module=angular.module("taigaRelatedTasks",[]),RelatedTaskRowDirective=function($repo,$compile,$confirm,$rootscope,$loading){var link,templateEdit,templateView;return templateView=_.template('
    \n
    \n \n \n #<%- task.ref %>\n <%- task.subject %>\n \n
    \n <% if(perms.modify_task) { %>\n \n <% } %>\n <% if(perms.delete_task) { %>\n \n <% } %>\n
    \n
    \n
    \n\n
    \n
    \n
    \n <% if(perms.modify_task) { %>\n \n <% } %>\n
    \n
    '),templateEdit=_.template('
    \n
    \n \n
    \n \n \n
    \n
    \n
    \n\n
    \n
    \n
    \n \n
    \n
    '),link=function($scope,$el,$attrs,$model){var renderEdit,renderView,saveTask;return saveTask=debounce(2e3,function(task){var promise;return task.subject=$el.find("input").val(),$loading.start($el.find(".task-name")),promise=$repo.save(task),promise.then(function(){return function(){return $loading.finish($el.find(".task-name")),$confirm.notify("success"),$rootscope.$broadcast("related-tasks:update")}}(this)),promise.then(null,function(){return function(){return $loading.finish($el.find(".task-name")),$el.find("input").val(task.subject),$confirm.notify("error")}}(this)),promise}),renderEdit=function(task){return $el.html($compile(templateEdit({task:task}))($scope)),$el.on("keyup","input",function(event){return 13===event.keyCode?saveTask($model.$modelValue).then(function(){return renderView($model.$modelValue)}):27===event.keyCode?renderView($model.$modelValue):void 0}),$el.on("click",".icon-floppy",function(){return saveTask($model.$modelValue).then(function(){return renderView($model.$modelValue)})}),$el.on("click",".cancel-edit",function(){return renderView($model.$modelValue)})},renderView=function(task){var perms;return $el.off(),perms={modify_task:-1!==$scope.project.my_permissions.indexOf("modify_task"),delete_task:-1!==$scope.project.my_permissions.indexOf("delete_task")},$el.html($compile(templateView({task:task,perms:perms}))($scope)),$el.on("click",".icon-edit",function(){return renderEdit($model.$modelValue),$el.find("input").focus().select()}),$el.on("click",".delete-task",function(){var message,title;return task=$model.$modelValue,title="Delete Task",message=task.subject,$confirm.askOnDelete(title,message).then(function(finish){var promise;return promise=$repo.remove(task),promise.then(function(){return finish(),$confirm.notify("success"),$scope.$emit("related-tasks:delete")}),promise.then(null,function(){return $confirm.notify("error")})})})},$scope.$watch($attrs.ngModel,function(val){return val?renderView(val):void 0}),$scope.$on("related-tasks:assigned-to-changed",function(){return $rootscope.$broadcast("related-tasks:update")}),$scope.$on("related-tasks:status-changed",function(){return $rootscope.$broadcast("related-tasks:update")}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgRelatedTaskRow",["$tgRepo","$compile","$tgConfirm","$rootScope","$tgLoading","$tgAnalytics",RelatedTaskRowDirective]),RelatedTaskCreateFormDirective=function($repo,$compile,$confirm,$tgmodel,$loading,$analytics){var link,newTask,template;return template=_.template('
    \n
    \n \n
    \n \n \n
    \n
    \n
    \n\n
    \n
    \n
    \n \n
    \n
    '),newTask={subject:"",assigned_to:null},link=function($scope,$el){var createTask,render;return createTask=debounce(2e3,function(task){var promise;return task.subject=$el.find("input").val(),task.assigned_to=$scope.newTask.assigned_to,task.status=$scope.newTask.status,$scope.newTask.status=$scope.project.default_task_status,$scope.newTask.assigned_to=null,$loading.start($el.find(".task-name")),promise=$repo.create("tasks",task),promise.then(function(){return $analytics.trackEvent("task","create","create task on userstory",1),$loading.finish($el.find(".task-name")),$scope.$emit("related-tasks:add"),$confirm.notify("success")}),promise.then(null,function(){return $el.find("input").val(task.subject),$loading.finish($el.find(".task-name")),$confirm.notify("error")}),promise}),render=function(){return $el.off(),$el.html($compile(template())($scope)),$el.find("input").focus().select(),$el.addClass("active"),$el.on("keyup","input",function(event){return 13===event.keyCode?createTask(newTask).then(function(){return render()}):27===event.keyCode?$el.html(""):void 0}),$el.on("click",".icon-delete",function(){return $el.html("")}),$el.on("click",".icon-floppy",function(){return createTask(newTask).then(function(){return $el.html("")})})},taiga.bindOnce($scope,"us",function(){return newTask.status=$scope.project.default_task_status,newTask.project=$scope.project.id,newTask.user_story=$scope.us.id,$scope.newTask=$tgmodel.make_model("tasks",newTask),$el.html("")}),$scope.$on("related-tasks:show-form",function(){return render()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskCreateForm",["$tgRepo","$compile","$tgConfirm","$tgModel","$tgLoading","$tgAnalytics",RelatedTaskCreateFormDirective]),RelatedTaskCreateButtonDirective=function(){var link,template;return template=_.template(''),link=function($scope,$el){return $scope.$watch("project",function(val){return val?($el.off(),$el.html(-1!==$scope.project.my_permissions.indexOf("add_task")?template():""),$el.on("click",".icon",function(){return $scope.$emit("related-tasks:add-new-clicked")})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskCreateButton",["$tgRepo","$compile","$tgConfirm","$tgModel",RelatedTaskCreateButtonDirective]),RelatedTasksDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){var loadTasks;return loadTasks=function(){return $rs.tasks.list($scope.projectId,null,$scope.usId).then(function(){return function(tasks){return $scope.tasks=tasks,tasks -}}(this))},$scope.$on("related-tasks:add",function(){return loadTasks().then(function(){return $rootscope.$broadcast("related-tasks:update")})}),$scope.$on("related-tasks:delete",function(){return loadTasks().then(function(){return $rootscope.$broadcast("related-tasks:update")})}),$scope.$on("related-tasks:add-new-clicked",function(){return $scope.$broadcast("related-tasks:show-form")}),taiga.bindOnce($scope,"us",function(){return loadTasks()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTasks",["$tgRepo","$tgResources","$rootScope",RelatedTasksDirective]),RelatedTaskAssignedToInlineEditionDirective=function($repo,$rootscope){var link,template;return template=_.template('<%- name %>\n
    <%- name %>
    '),link=function($scope,$el,$attrs){var $ctrl,autoSave,notAutoSave,task,updateRelatedTask;return updateRelatedTask=function(task){var ctx,member;return ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=$scope.usersById[task.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name_display),$el.find(".avatar").html(template(ctx)),$el.find(".task-assignedto").attr("title",ctx.name)},$ctrl=$el.controller(),task=$scope.$eval($attrs.tgRelatedTaskAssignedToInlineEdition),notAutoSave=$scope.$eval($attrs.notAutoSave),autoSave=!notAutoSave,updateRelatedTask(task),$el.on("click",".task-assignedto",function(){return $rootscope.$broadcast("assigned-to:add",task)}),taiga.bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_task")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("assigned-to:added",debounce(2e3,function(){return function(ctx,userId,updatedRelatedTask){return updatedRelatedTask.id===task.id?(updatedRelatedTask.assigned_to=userId,autoSave&&$repo.save(updatedRelatedTask).then(function(){return $scope.$emit("related-tasks:assigned-to-changed")}),updateRelatedTask(updatedRelatedTask)):void 0}}(this))),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskAssignedToInlineEdition",["$tgRepo","$rootScope",RelatedTaskAssignedToInlineEditionDirective])}.call(this),function(){var ResourcesService,initResources,initUrls,module,taiga,urls,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,ResourcesService=function(_super){function ResourcesService(){return ResourcesService.__super__.constructor.apply(this,arguments)}return __extends(ResourcesService,_super),ResourcesService}(taiga.Service),urls={auth:"/auth","auth-register":"/auth/register",invitations:"/invitations",permissions:"/permissions",roles:"/roles",projects:"/projects",memberships:"/memberships","notify-policies":"/notify-policies","bulk-create-memberships":"/memberships/bulk_create",milestones:"/milestones",userstories:"/userstories","bulk-create-us":"/userstories/bulk_create","bulk-update-us-backlog-order":"/userstories/bulk_update_backlog_order","bulk-update-us-sprint-order":"/userstories/bulk_update_sprint_order","bulk-update-us-kanban-order":"/userstories/bulk_update_kanban_order","userstories-restore":"/userstories/%s/restore",tasks:"/tasks","bulk-create-tasks":"/tasks/bulk_create","bulk-update-task-taskboard-order":"/tasks/bulk_update_taskboard_order","tasks-restore":"/tasks/%s/restore",issues:"/issues","bulk-create-issues":"/issues/bulk_create","issues-restore":"/issues/%s/restore",wiki:"/wiki","wiki-restore":"/wiki/%s/restore","wiki-links":"/wiki-links","choices/userstory-statuses":"/userstory-statuses","choices/userstory-statuses/bulk-update-order":"/userstory-statuses/bulk_update_order","choices/points":"/points","choices/points/bulk-update-order":"/points/bulk_update_order","choices/task-statuses":"/task-statuses","choices/task-statuses/bulk-update-order":"/task-statuses/bulk_update_order","choices/issue-statuses":"/issue-statuses","choices/issue-statuses/bulk-update-order":"/issue-statuses/bulk_update_order","choices/issue-types":"/issue-types","choices/issue-types/bulk-update-order":"/issue-types/bulk_update_order","choices/priorities":"/priorities","choices/priorities/bulk-update-order":"/priorities/bulk_update_order","choices/severities":"/severities","choices/severities/bulk-update-order":"/severities/bulk_update_order",search:"/search",sites:"/sites","project-templates":"/project-templates","site-members":"/site-members","site-projects":"/site-projects",users:"/users","users-password-recovery":"/users/password_recovery","users-change-password-from-recovery":"/users/change_password_from_recovery","users-change-password":"/users/change_password","users-change-email":"/users/change_email","users-cancel-account":"/users/cancel","user-storage":"/user-storage",resolver:"/resolver","userstory-statuses":"/userstory-statuses",points:"/points","task-statuses":"/task-statuses","issue-statuses":"/issue-statuses","issue-types":"/issue-types",priorities:"/priorities",severities:"/severities","project-modules":"/projects/%s/modules","history/us":"/history/userstory","history/issue":"/history/issue","history/task":"/history/task","history/wiki":"/history/wiki","attachments/us":"/userstories/attachments","attachments/issue":"/issues/attachments","attachments/task":"/tasks/attachments","attachments/wiki_page":"/wiki/attachments",feedback:"/feedback"},initUrls=function($log,$urls){return $log.debug("Initialize api urls"),$urls.update(urls)},initResources=function($log,$rs){var provider,providers,_i,_len,_results;for($log.debug("Initialize resources"),providers=_.toArray(arguments).slice(2),_results=[],_i=0,_len=providers.length;_len>_i;_i++)provider=providers[_i],_results.push(provider($rs));return _results},module=angular.module("taigaResources",["taigaBase"]),module.service("$tgResources",ResourcesService),module.run(["$log","$tgUrls",initUrls]),module.run(["$log","$tgResources","$tgProjectsResourcesProvider","$tgMembershipsResourcesProvider","$tgNotifyPoliciesResourcesProvider","$tgInvitationsResourcesProvider","$tgRolesResourcesProvider","$tgUserSettingsResourcesProvider","$tgSprintsResourcesProvider","$tgUserstoriesResourcesProvider","$tgTasksResourcesProvider","$tgIssuesResourcesProvider","$tgWikiResourcesProvider","$tgSearchResourcesProvider","$tgAttachmentsResourcesProvider","$tgMdRenderResourcesProvider","$tgHistoryResourcesProvider","$tgKanbanResourcesProvider","$tgModulesResourcesProvider",initResources])}.call(this),function(){var SearchBoxDirective,SearchController,SearchDirective,bindOnce,debounce,debounceLeading,groupBy,mixOf,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,mixOf=this.taiga.mixOf,debounceLeading=this.taiga.debounceLeading,trim=this.taiga.trim,debounce=this.taiga.debounce,module=angular.module("taigaSearch",[]),SearchController=function(_super){function SearchController(scope,repo,rs,params,q,location,appTitle,navUrls,tgLoader){var loadSearchData,promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.tgLoader=tgLoader,this.scope.sectionName="Search",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Search")}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.searchTerm="",loadSearchData=debounceLeading(100,function(_this){return function(t){return _this.loadSearchData(t)}}(this)),this.scope.$watch("searchTerm",function(_this){return function(term){return term?loadSearchData(term):_this.tgLoader.pageLoaded()}}(this))}return __extends(SearchController,_super),SearchController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","tgLoader"],SearchController.prototype.loadFilters=function(){var defered;return defered=this.q.defer(),defered.resolve(),defered.promise},SearchController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issueStatusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.taskStatusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),project}}(this))},SearchController.prototype.loadSearchData=function(term){var promise;return promise=this.rs.search["do"](this.scope.projectId,term).then(function(_this){return function(data){return _this.scope.searchResults=data,data}}(this)),promise["finally"](function(_this){return function(){return _this.tgLoader.pageLoaded()}}(this)),promise},SearchController.prototype.loadInitialData=function(){return this.loadProject().then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.fillUsersAndRoles(project.users,project.roles)}}(this))},SearchController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("SearchController",SearchController),SearchBoxDirective=function($lightboxService,$navurls,$location,$route){var link;return link=function($scope,$el){var project,submit;return project=null,submit=debounce(2e3,function(){return function(event){var form,text,url;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?(text=$el.find("#search-text").val(),url=$navurls.resolve("project-search",{project:project.slug}),$lightboxService.close($el),$scope.$apply(function(){return $location.path(url),$location.search("text",text).path(url),$route.reload()})):void 0}}(this)),$scope.$on("search-box:show",function(ctx,newProject){return project=newProject,$lightboxService.open($el),$el.find("#search-text").val("")}),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgSearchBox",["lightboxService","$tgNavUrls","$tgLocation","$route",SearchBoxDirective]),SearchDirective=function($log,$compile,$templatecache,$routeparams,$location){var link,linkTable;return linkTable=function($scope,$el){var getActiveSection,lastSeatchResults,markSectionTabActive,renderFilterTabs,renderTableContent,tabsDom,templates;return tabsDom=$el.find("section.search-filter"),lastSeatchResults=null,getActiveSection=function(data){var maxVal,name,selectedSectionData,selectedSectionName,value;maxVal=0,selectedSectionName=null,selectedSectionData=null;for(name in data)value=data[name],"count"!==name&&value.length>maxVal&&(maxVal=value.length,selectedSectionName=name,selectedSectionData=value);return 0===maxVal?{name:"userstories",value:[]}:{name:selectedSectionName,value:selectedSectionData}},renderFilterTabs=function(data){var name,value,_results;_results=[];for(name in data)value=data[name],"count"!==name&&_results.push(tabsDom.find("li."+name+" .num").html(value.length));return _results},markSectionTabActive=function(section){return tabsDom.find("a.active").removeClass("active"),tabsDom.find("li."+section.name+" a").addClass("active")},templates={issues:$templatecache.get("search-issues"),tasks:$templatecache.get("search-tasks"),userstories:$templatecache.get("search-userstories"),wikipages:$templatecache.get("search-wikipages")},renderTableContent=function(section){var element,oldElements,oldScope,scope,template;return oldElements=$el.find(".search-result-table").children(),oldScope=oldElements.scope(),oldScope&&(oldScope.$destroy(),oldElements.remove()),scope=$scope.$new(),scope[section.name]=section.value,template=angular.element.parseHTML(trim(templates[section.name])),element=$compile(template)(scope),$el.find(".search-result-table").html(element)},$scope.$watch("searchResults",function(data){var activeSection;return lastSeatchResults=data,activeSection=getActiveSection(data),renderFilterTabs(data),renderTableContent(activeSection),markSectionTabActive(activeSection)}),$scope.$watch("searchTerm",function(searchTerm){return searchTerm?$location.search("text",searchTerm):void 0}),$el.on("click",".search-filter li > a",function(event){var section,sectionData,sectionName,target;return event.preventDefault(),target=angular.element(event.currentTarget),sectionName=target.parent().data("name"),sectionData=lastSeatchResults[sectionName],section={name:sectionName,value:sectionData},$scope.$apply(function(){return renderTableContent(section),markSectionTabActive(section)})})},link=function($scope,$el,$attrs){var $ctrl,searchText;return $ctrl=$el.controller(),linkTable($scope,$el,$attrs,$ctrl),searchText=$routeparams.text,$scope.$watch("projectId",function(projectId){return null!=projectId?$scope.searchTerm=searchText:void 0})},{link:link}},module.directive("tgSearch",["$log","$compile","$templateCache","$routeParams","$tgLocation",SearchDirective])}.call(this),function(){var module;module=angular.module("taigaTaskboard",[])}.call(this),function(){var module;module=angular.module("taigaTasks",[])}.call(this),function(){var module;module=angular.module("taigaTeam",[])}.call(this),function(){var module;module=angular.module("taigaUserSettings",[])}.call(this),function(){var module;module=angular.module("taigaUserStories",[])}.call(this),function(){var module;module=angular.module("taigaWiki",[])}.call(this),function(){var AnalyticsService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,module=angular.module("taigaCommon"),AnalyticsService=function(_super){function AnalyticsService(rootscope,log,config,win,doc,location){var conf;this.rootscope=rootscope,this.log=log,this.config=config,this.win=win,this.doc=doc,this.location=location,this.initialized=!1,conf=this.config.get("analytics",{}),this.accountId=conf.accountId,this.pageEvent=conf.pageEvent||"$routeChangeSuccess",this.trackRoutes=conf.trackRoutes||!0,this.ignoreFirstPageLoad=conf.ignoreFirstPageLoad||!1}return __extends(AnalyticsService,_super),AnalyticsService.$inject=["$rootScope","$log","$tgConfig","$window","$document","$location"],AnalyticsService.prototype.initialize=function(){return this.accountId?(this.injectAnalytics(),this.win.ga("create",this.accountId,"auto"),this.win.ga("require","displayfeatures"),this.trackRoutes&&!this.ignoreFirstPageLoad&&this.win.ga("send","pageview",this.getUrl()),this.trackRoutes&&this.rootscope.$on(this.pageEvent,function(_this){return function(){return _this.trackPage(_this.getUrl(),"Taiga")}}(this)),this.initialized=!0):void this.log.debug("Analytics: no acount id provided. Disabling.")},AnalyticsService.prototype.getUrl=function(){return this.location.path()},AnalyticsService.prototype.injectAnalytics=function(){var fn;return(fn=function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r,i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date,a=s.createElement(o),m=s.getElementsByTagName(o)[0],a.async=1,a.src=g,m.parentNode.insertBefore(a,m)})(window,document,"script","//www.google-analytics.com/analytics.js","ga")},AnalyticsService.prototype.trackPage=function(url,title){return this.initialized&&this.win.ga?(title=title||this.doc[0].title,this.win.ga("send","pageview",{page:url,title:title})):void 0},AnalyticsService.prototype.trackEvent=function(category,action,label,value){return this.initialized&&this.win.ga?this.win.ga("send","event",category,action,label,value):void 0},AnalyticsService}(taiga.Service),module.service("$tgAnalytics",AnalyticsService)}.call(this),function(){var AttachmentDirective,AttachmentsController,AttachmentsDirective,bindMethods,bindOnce,module,sizeFormat,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,bindOnce=this.taiga.bindOnce,bindMethods=this.taiga.bindMethods,module=angular.module("taigaCommon"),AttachmentsController=function(_super){function AttachmentsController(scope,rootscope,repo,rs,confirm,q){this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.rs=rs,this.confirm=confirm,this.q=q,bindMethods(this),this.type=null,this.objectId=null,this.projectId=null,this.uploadingAttachments=[],this.attachments=[],this.attachmentsCount=0,this.deprecatedAttachmentsCount=0,this.showDeprecated=!1}return __extends(AttachmentsController,_super),AttachmentsController.$inject=["$scope","$rootScope","$tgRepo","$tgResources","$tgConfirm","$q"],AttachmentsController.prototype.initialize=function(type,objectId){return this.type=type,this.objectId=objectId,this.projectId=this.scope.projectId},AttachmentsController.prototype.loadAttachments=function(){var urlname;return this.objectId?(urlname="attachments/"+this.type,this.rs.attachments.list(urlname,this.objectId,this.projectId).then(function(_this){return function(attachments){return _this.attachments=_.sortBy(attachments,"order"),_this.updateCounters(),attachments}}(this))):this.attachments},AttachmentsController.prototype.updateCounters=function(){return this.attachmentsCount=this.attachments.length,this.deprecatedAttachmentsCount=_.filter(this.attachments,{is_deprecated:!0}).length},AttachmentsController.prototype._createAttachment=function(attachment){var promise,urlName;return urlName="attachments/"+this.type,promise=this.rs.attachments.create(urlName,this.projectId,this.objectId,attachment),promise=promise.then(function(_this){return function(data){var index;return data.isCreatedRightNow=!0,index=_this.uploadingAttachments.indexOf(attachment),_this.uploadingAttachments.splice(index,1),_this.attachments.push(data),_this.rootscope.$broadcast("attachment:create")}}(this)),promise=promise.then(null,function(_this){return function(data){var index;return 413===data.status&&_this.scope.$emit("attachments:size-error"),index=_this.uploadingAttachments.indexOf(attachment),_this.uploadingAttachments.splice(index,1),_this.confirm.notify("error","We have not been able to upload '"+attachment.name+"'. "+data.data._error_message),_this.q.reject(data)}}(this))},AttachmentsController.prototype.createAttachments=function(attachments){var promises;return promises=_.map(attachments,function(_this){return function(x){return _this._createAttachment(x)}}(this)),this.q.all(promises).then(function(_this){return function(){return _this.updateCounters()}}(this))},AttachmentsController.prototype.addUploadingAttachments=function(attachments){return this.uploadingAttachments=_.union(this.uploadingAttachments,attachments)},AttachmentsController.prototype.reorderAttachment=function(attachment,newIndex){var oldIndex;return oldIndex=this.attachments.indexOf(attachment),oldIndex!==newIndex?(this.attachments.splice(oldIndex,1),this.attachments.splice(newIndex,0,attachment),_.each(this.attachments,function(x,i){return x.order=i+1})):void 0},AttachmentsController.prototype.updateAttachment=function(attachment){var onError,onSuccess;return onSuccess=function(_this){return function(){return _this.updateCounters(),_this.rootscope.$broadcast("attachment:edit")}}(this),onError=function(_this){return function(response){return 413===response.status&&$scope.$emit("attachments:size-error"),_this.confirm.notify("error"),_this.q.reject()}}(this),this.repo.save(attachment).then(onSuccess,onError)},AttachmentsController.prototype.saveAttachments=function(){return this.repo.saveAll(this.attachments).then(null,function(_this){return function(){var item,_i,_len,_ref;for(_ref=_this.attachments,_i=0,_len=_ref.length;_len>_i;_i++)item=_ref[_i],item.revert();return _this.attachments=_.sorBy(_this.attachments,"order")}}(this))},AttachmentsController.prototype.removeAttachment=function(attachment){var message,title;return title="Delete attachment",message="the attachment '"+attachment.name+"'",this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var onError,onSuccess;return onSuccess=function(){var index;return finish(),index=_this.attachments.indexOf(attachment),_this.attachments.splice(index,1),_this.updateCounters(),_this.rootscope.$broadcast("attachment:delete")},onError=function(){return finish(!1),_this.confirm.notify("error",null,"We have not been able to delete "+message+"."),_this.q.reject()},_this.repo.remove(attachment).then(onSuccess,onError)}}(this))},AttachmentsController.prototype.filterAttachments=function(item){return this.showDeprecated?!0:!item.is_deprecated},AttachmentsController}(taiga.Controller),AttachmentsDirective=function($config){var link,template,templateFn;return template=_.template('
    \n
    \n

    \n \n attachments\n

    \n
    \n <% if (maxFileSize){ %>\n \n <% }; %>\n \n \n
    \n
    \n\n \n
    '),link=function($scope,$el,$attrs,$ctrls){var $ctrl,$model,showSizeInfo,tdom;return $ctrl=$ctrls[0],$model=$ctrls[1],bindOnce($scope,$attrs.ngModel,function(value){return $ctrl.initialize($attrs.type,value.id),$ctrl.loadAttachments()}),tdom=$el.find("div.attachment-body.sortable"),tdom.sortable({items:"div.single-attachment",handle:"a.settings.icon.icon-drag-v",containment:".attachments",dropOnEmpty:!0,scroll:!1,tolerance:"pointer",placeholder:"sortable-placeholder single-attachment"}),tdom.on("sortstop",function(event,ui){var attachment,newIndex;return attachment=ui.item.scope().attach,newIndex=ui.item.index(),$ctrl.reorderAttachment(attachment,newIndex),$ctrl.saveAttachments()}),showSizeInfo=function(){return $el.find(".size-info").removeClass("hidden")},$scope.$on("attachments:size-error",function(){return showSizeInfo()}),$el.on("change",".attachments-header input",function(event){var files;return files=_.toArray(event.target.files),files.length<1?void 0:$scope.$apply(function(){return $ctrl.addUploadingAttachments(files),$ctrl.createAttachments(files)})}),$el.on("click",".more-attachments",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $ctrl.showDeprecated=!$ctrl.showDeprecated}),target.find("span.text").addClass("hidden"),$ctrl.showDeprecated?(target.find("span[data-type=hide]").removeClass("hidden"),target.find("more-attachments-num").addClass("hidden")):(target.find("span[data-type=show]").removeClass("hidden"),target.find("more-attachments-num").removeClass("hidden"))}),$scope.$on("$destroy",function(){return $el.off()})},templateFn=function($el,$attrs){var ctx,maxFileSize,maxFileSizeMsg;return maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&(maxFileSize=sizeFormat(maxFileSize)),maxFileSizeMsg=maxFileSize?"Maximum upload size is "+maxFileSize:"",ctx={type:$attrs.type,maxFileSize:maxFileSize,maxFileSizeMsg:maxFileSizeMsg},template(ctx)},{require:["tgAttachments","ngModel"],controller:AttachmentsController,controllerAs:"ctrl",restrict:"AE",scope:!0,link:link,template:templateFn}},module.directive("tgAttachments",["$tgConfig","$tgConfirm",AttachmentsDirective]),AttachmentDirective=function(){var link,template,templateEdit;return template=_.template('\n
    \n <%- size %>\n
    \n
    \n <% if (isDeprecated){ %> (deprecated) <% } %>\n <%- description %>\n
    \n<% if (modifyPermission) {%>\n
    \n \n \n \n
    \n<% } %>'),templateEdit=_.template('
    \n \n <%- name %>\n
    \n
    \n <%- size %>\n
    \n
    \n \n
    \n
    \n checked<% } %> />\n \n
    \n
    \n \n \n
    '),link=function($scope,$el,$attrs,$ctrl){var attachment,render,saveAttachment;return render=function(attachment,edit){var ctx,html,modifyPermission,permissions;return null==edit&&(edit=!1),permissions=$scope.project.my_permissions,modifyPermission=permissions.indexOf("modify_"+$ctrl.type)>-1,ctx={id:attachment.id,name:attachment.name,created_date:moment(attachment.created_date).format("DD MMM YYYY [at] hh:mm"),url:attachment.url,size:sizeFormat(attachment.size),description:attachment.description,isDeprecated:attachment.is_deprecated,modifyPermission:modifyPermission},html=edit?templateEdit(ctx):template(ctx),$el.html(html),attachment.is_deprecated?$el.addClass("deprecated"):void 0},saveAttachment=function(){return attachment.description=$el.find("input[name='description']").val(),attachment.is_deprecated=$el.find("input[name='is-deprecated']").prop("checked"),$scope.$apply(function(){return $ctrl.updateAttachment(attachment).then(function(){return render(attachment,!1)})})},$el.on("click","a.editable-settings.icon-floppy",function(event){return event.preventDefault(),saveAttachment()}),$el.on("keyup","input[name=description]",function(event){return 13===event.keyCode?saveAttachment():27===event.keyCode?render(attachment,!1):void 0}),$el.on("click","a.editable-settings.icon-delete",function(event){return event.preventDefault(),render(attachment,!1)}),$el.on("click","a.settings.icon-edit",function(event){return event.preventDefault(),render(attachment,!0),$el.find("input[name='description']").focus().select()}),$el.on("click","a.settings.icon-delete",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.removeAttachment(attachment)})}),$scope.$on("$destroy",function(){return $el.off()}),attachment=$scope.$eval($attrs.tgAttachment),render(attachment,attachment.isCreatedRightNow),attachment.isCreatedRightNow?$el.find("input[name='description']").focus().select():void 0},{link:link,require:"^tgAttachments",restrict:"AE"}},module.directive("tgAttachment",AttachmentDirective)}.call(this),function(){var AssignedToDirective,BlockButtonDirective,CreatedByDisplayDirective,DateRangeDirective,DateSelectorDirective,DeleteButtonDirective,EditableDescriptionDirective,EditableSubjectDirective,ListItemAssignedtoDirective,ListItemIssueStatusDirective,ListItemPriorityDirective,ListItemSeverityDirective,ListItemTaskStatusDirective,ListItemTypeDirective,ListItemUsStatusDirective,SprintProgressBarDirective,TgMainTitleDirective,TgProgressBarDirective,WatchersDirective,bindOnce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),DateRangeDirective=function(){var link,renderRange;return renderRange=function($el,first,second){var endDate,initDate;return initDate=moment(first).format("DD MMM YYYY"),endDate=moment(second).format("DD MMM YYYY"),$el.html(""+initDate+"-"+endDate)},link=function($scope,$el,$attrs){var first,second,_ref;return _ref=$attrs.tgDateRange.split(","),first=_ref[0],second=_ref[1],bindOnce($scope,first,function(valFirst){return bindOnce($scope,second,function(valSecond){return renderRange($el,valFirst,valSecond)})})},{link:link}},module.directive("tgDateRange",DateRangeDirective),DateSelectorDirective=function(){var link;return link=function($scope,$el,$attrs){var selectedDate;return selectedDate=null,$el.picker=new Pikaday({field:$el[0],format:"DD MMM YYYY",onSelect:function(){return function(date){return selectedDate=date}}(this),onOpen:function(){return function(){return null!=selectedDate?$el.picker.setDate(selectedDate):void 0}}(this)}),$scope.$watch($attrs.ngModel,function(val){return null!=val?$el.picker.setDate(val):void 0})},{link:link,require:"ngModel"}},module.directive("tgDateSelector",DateSelectorDirective),SprintProgressBarDirective=function(){var link,renderProgress;return renderProgress=function($el,percentage,visual_percentage){return $el.hasClass(".current-progress")?$el.css("width",""+percentage+"%"):($el.find(".current-progress").css("width",""+visual_percentage+"%"),$el.find(".number").html(""+percentage+" %"))},link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgSprintProgressbar,function(sprint){var closedPoints,percentage,totalPoints,visual_percentage;return closedPoints=sprint.closed_points,totalPoints=sprint.total_points,percentage=0,0!==totalPoints&&(percentage=Math.round(100*(closedPoints/totalPoints))),visual_percentage=0,0!==totalPoints&&(visual_percentage=Math.round(98*(closedPoints/totalPoints))),renderProgress($el,percentage,visual_percentage) -})},{link:link}},module.directive("tgSprintProgressbar",SprintProgressBarDirective),CreatedByDisplayDirective=function(){var link,template;return template=_.template('
    \n <%- owner.full_name_display %>\n
    \n\n
    \n Created by <%- owner.full_name_display %>\n <%- date %>\n
    '),link=function($scope,$el,$attrs){var render;return render=function(model){var html,owner,_ref;return owner=(null!=(_ref=$scope.usersById)?_ref[model.owner]:void 0)||{full_name_display:"external user",photo:"/images/unnamed.png"},html=template({owner:owner,date:moment(model.created_date).format("DD MMM YYYY HH:mm")}),$el.html(html)},bindOnce($scope,$attrs.ngModel,function(model){return null!=model?render(model):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgCreatedByDisplay",CreatedByDisplayDirective),WatchersDirective=function($rootscope,$confirm,$repo,$qqueue){var link,template;return template=_.template('<% if(isEditable){ %>\n
    \n watchers\n \n
    \n<% } else if(watchers.length > 0){ %>\n
    \n watchers\n
    \n<% }; %>\n\n<% _.each(watchers, function(watcher) { %>\n<% if(watcher) { %>\n
    \n
    \n \n <%- watcher.full_name_display %>\n \n
    \n
    \n <%- watcher.full_name_display %>\n\n <% if(isEditable){ %>\n \n \n <% }; %>\n
    \n
    \n<% } %>\n<% }); %>'),link=function($scope,$el,$attrs,$model){var deleteWatcher,isEditable,renderWatchers,save;return isEditable=function(){var _ref,_ref1;return-1!==(null!=(_ref=$scope.project)&&null!=(_ref1=_ref.my_permissions)?_ref1.indexOf($attrs.requiredPerm):void 0)},save=$qqueue.bindAdd(function(){return function(watchers){var item,promise;return item=$model.$modelValue.clone(),item.watchers=watchers,$model.$setViewValue(item),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),watchers=_.map(watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $model.$modelValue.revert()})}}(this)),deleteWatcher=$qqueue.bindAdd(function(){return function(watcherIds){var item,promise;return item=$model.$modelValue.clone(),item.watchers=watcherIds,$model.$setViewValue(item),promise=$repo.save($model.$modelValue),promise.then(function(){var watchers;return $confirm.notify("success"),watchers=_.map(item.watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return item.revert(),$confirm.notify("error")})}}(this)),renderWatchers=function(watchers){var ctx,html;return ctx={watchers:watchers,isEditable:isEditable()},html=template(ctx),$el.html(html),isEditable()&&0===watchers.length?($el.find(".title").text("Add watchers"),$el.find(".watchers-header").addClass("no-watchers")):void 0},$el.on("click",".icon-delete",function(event){var message,target,title,watcherId;return event.preventDefault(),isEditable()?(target=angular.element(event.currentTarget),watcherId=target.data("watcher-id"),title="Delete watcher",message=$scope.usersById[watcherId].full_name_display,$confirm.askOnDelete(title,message).then(function(){return function(finish){var watcherIds;return finish(),watcherIds=_.clone($model.$modelValue.watchers,!1),watcherIds=_.pull(watcherIds,watcherId),deleteWatcher(watcherIds)}}(this))):void 0}),$el.on("click",".add-watcher",function(event){return event.preventDefault(),isEditable()?$scope.$apply(function(){return $rootscope.$broadcast("watcher:add",$model.$modelValue)}):void 0}),$scope.$on("watcher:added",function(ctx,watcherId){var watchers;return watchers=_.clone($model.$modelValue.watchers,!1),watchers.push(watcherId),watchers=_.uniq(watchers),save(watchers)}),$scope.$watch($attrs.ngModel,function(item){var watchers;if(null!=item)return watchers=_.map(item.watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgWatchers",["$rootScope","$tgConfirm","$tgRepo","$tgQqueue",WatchersDirective]),AssignedToDirective=function($rootscope,$confirm,$repo,$loading,$qqueue){var link,template;return template=_.template('<% if (assignedTo) { %>\n
    \n <%- assignedTo.full_name_display %>\n
    \n<% } %>\n\n'),link=function($scope,$el,$attrs,$model){var isEditable,renderAssignedTo,save;return isEditable=function(){var _ref,_ref1;return-1!==(null!=(_ref=$scope.project)&&null!=(_ref1=_ref.my_permissions)?_ref1.indexOf($attrs.requiredPerm):void 0)},save=$qqueue.bindAdd(function(){return function(userId){var promise;return $model.$modelValue.assigned_to=userId,$loading.start($el),promise=$repo.save($model.$modelValue),promise.then(function(){return $loading.finish($el),$confirm.notify("success"),renderAssignedTo($model.$modelValue),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $model.$modelValue.revert(),$confirm.notify("error"),$loading.finish($el)}),promise}}(this)),renderAssignedTo=function(issue){var assignedTo,assignedToId,ctx,html;return assignedToId=null!=issue?issue.assigned_to:void 0,assignedTo=null!=assignedToId?$scope.usersById[assignedToId]:null,ctx={assignedTo:assignedTo,isEditable:isEditable()},html=template(ctx),$el.html(html)},$el.on("click",".user-assigned",function(event){return event.preventDefault(),isEditable()?$scope.$apply(function(){return $rootscope.$broadcast("assigned-to:add",$model.$modelValue)}):void 0}),$el.on("click",".icon-delete",function(event){var title;return event.preventDefault(),isEditable()?(title="Are you sure you want to leave it unassigned?",$confirm.ask(title).then(function(){return function(finish){return finish(),$model.$modelValue.assigned_to=null,save(null)}}(this))):void 0}),$scope.$on("assigned-to:added",function(ctx,userId,item){return item.id===$model.$modelValue.id?save(userId):void 0}),$scope.$watch($attrs.ngModel,function(instance){return renderAssignedTo(instance)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgAssignedTo",["$rootScope","$tgConfirm","$tgRepo","$tgLoading","$tgQqueue",AssignedToDirective]),BlockButtonDirective=function($rootscope,$loading){var link,template;return template='Block\nUnblock',link=function($scope,$el,$attrs,$model){var isEditable;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},$scope.$watch($attrs.ngModel,function(item){return item?(isEditable()&&$el.find(".item-block").addClass("editable"),item.is_blocked?($el.find(".item-block").hide(),$el.find(".item-unblock").show()):($el.find(".item-block").show(),$el.find(".item-unblock").hide())):void 0}),$el.on("click",".item-block",function(event){return event.preventDefault(),$rootscope.$broadcast("block",$model.$modelValue)}),$el.on("click",".item-unblock",function(event){var finish;return event.preventDefault(),$loading.start($el.find(".item-unblock")),finish=function(){return $loading.finish($el.find(".item-unblock"))},$rootscope.$broadcast("unblock",$model.$modelValue,finish)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgBlockButton",["$rootScope","$tgLoading",BlockButtonDirective]),DeleteButtonDirective=function($log,$repo,$confirm,$location){var link,template;return template='Delete',link=function($scope,$el,$attrs,$model){return $attrs.onDeleteGoToUrl?$attrs.onDeleteTitle?($el.on("click",".button",function(){var subtitle,title;return title=$scope.$eval($attrs.onDeleteTitle),subtitle=$model.$modelValue.subject,$confirm.askOnDelete(title,subtitle).then(function(){return function(finish){var promise;return promise=$repo.remove($model.$modelValue),promise.then(function(){var url;return finish(),url=$scope.$eval($attrs.onDeleteGoToUrl),$location.path(url)}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})}}(this))}),$scope.$on("$destroy",function(){return $el.off()})):$log.error("DeleteButtonDirective requires on-delete-title set in scope."):$log.error("DeleteButtonDirective requires on-delete-go-to-url set in scope.")},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgDeleteButton",["$log","$tgRepo","$tgConfirm","$tgLocation",DeleteButtonDirective]),EditableSubjectDirective=function($rootscope,$repo,$confirm,$loading,$qqueue){var link,template;return template='
    \n {{ item.subject }}\n \n
    \n',link=function($scope,$el,$attrs,$model){var isEditable,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},save=$qqueue.bindAdd(function(){return function(subject){var promise;return $model.$modelValue.subject=subject,$loading.start($el.find(".save-container")),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$el.find(".edit-subject").hide(),$el.find(".view-subject").show()}),promise.then(null,function(){return $confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find(".save-container"))}),promise}}(this)),$el.click(function(){return isEditable()?($el.find(".edit-subject").show(),$el.find(".view-subject").hide(),$el.find("input").focus()):void 0}),$el.on("click",".save",function(){var subject;return subject=$scope.item.subject,save(subject)}),$el.on("keyup","input",function(event){var subject;return 13===event.keyCode?(subject=$scope.item.subject,save(subject)):27===event.keyCode?($scope.$apply(function(){return function(){return $model.$modelValue.revert()}}(this)),$el.find("div.edit-subject").hide(),$el.find("div.view-subject").show()):void 0}),$el.find("div.edit-subject").hide(),$el.find("div.view-subject span.edit").hide(),$scope.$watch($attrs.ngModel,function(value){return value?($scope.item=value,isEditable()?void 0:$el.find(".view-subject .edit").remove()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgEditableSubject",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",EditableSubjectDirective]),EditableDescriptionDirective=function($rootscope,$repo,$confirm,$compile,$loading,$selectedText,$qqueue){var link,noDescriptionMegEditMode,noDescriptionMegReadMode,template;return template='
    \n
    \n \n
    \n
    ',noDescriptionMegEditMode='

    \n Empty space is so boring...\n go on be descriptive...\n A rose by any other name would smell as sweet...\n

    ',noDescriptionMegReadMode='

    \n No description yet.\n

    ',link=function($scope,$el,$attrs,$model){var isEditable,save;return $el.find(".edit-description").hide(),$el.find(".view-description .edit").hide(),isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},save=$qqueue.bindAdd(function(){return function(description){var promise;return $model.$modelValue.description=description,$loading.start($el.find(".save-container")),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$el.find(".edit-description").hide(),$el.find(".view-description").show()}),promise.then(null,function(){return $confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find(".save-container"))})}}(this)),$el.on("mouseup",".view-description",function(event){var target;return target=angular.element(event.target),!isEditable()||target.is("a")||$selectedText.get().length?void 0:($el.find(".edit-description").show(),$el.find(".view-description").hide(),$el.find("textarea").focus())}),$el.on("click",".save",function(){var description;return description=$scope.item.description,save(description)}),$el.on("keydown","textarea",function(event){return 27===event.keyCode?($scope.$apply(function(){return function(){return $scope.item.revert()}}(this)),$el.find(".edit-description").hide(),$el.find(".view-description").show()):void 0}),$scope.$watch($attrs.ngModel,function(value){return value?($scope.item=value,isEditable()?($el.find(".view-description .edit").show(),$el.find(".view-description .us-content").addClass("editable"),$scope.noDescriptionMsg=noDescriptionMegEditMode):$scope.noDescriptionMsg=noDescriptionMegReadMode):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgEditableDescription",["$rootScope","$tgRepo","$tgConfirm","$compile","$tgLoading","$selectedText","$tgQqueue",EditableDescriptionDirective]),ListItemIssueStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var issue;return issue=$scope.$eval($attrs.tgListitemIssueStatus),bindOnce($scope,"issueStatusById",function(issueStatusById){return $el.html(issueStatusById[issue.status].name)})},{link:link}},ListItemTaskStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var task;return task=$scope.$eval($attrs.tgListitemTaskStatus),bindOnce($scope,"taskStatusById",function(taskStatusById){return $el.html(taskStatusById[task.status].name)})},{link:link}},ListItemUsStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var us;return us=$scope.$eval($attrs.tgListitemUsStatus),bindOnce($scope,"usStatusById",function(usStatusById){return $el.html(usStatusById[us.status].name)})},{link:link}},ListItemAssignedtoDirective=function(){var link,template;return template=_.template('
    \n <%- name %>\n
    <%- name %>
    \n
    '),link=function($scope,$el,$attrs){return bindOnce($scope,"membersById",function(membersById){var ctx,item,member;return item=$scope.$eval($attrs.tgListitemAssignedto),ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=membersById[item.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name),$el.html(template(ctx))})},{link:link}},ListItemPriorityDirective=function(){var link,template;return template='
    ',link=function($scope,$el,$attrs){var render;return render=function(priorityById,issue){var domNode,priority;return priority=priorityById[issue.priority],domNode=$el.find(".level"),domNode.css("background-color",priority.color),domNode.attr("title",priority.name)},bindOnce($scope,"priorityById",function(priorityById){var issue;return issue=$scope.$eval($attrs.tgListitemPriority),render(priorityById,issue)}),$scope.$watch($attrs.tgListitemPriority,function(issue){return render($scope.priorityById,issue)})},{link:link,template:template}},ListItemSeverityDirective=function(){var link,template;return template='
    ',link=function($scope,$el,$attrs){var render;return render=function(severityById,issue){var domNode,severity;return severity=severityById[issue.severity],domNode=$el.find(".level"),domNode.css("background-color",severity.color),domNode.attr("title",severity.name)},bindOnce($scope,"severityById",function(severityById){var issue;return issue=$scope.$eval($attrs.tgListitemSeverity),render(severityById,issue)}),$scope.$watch($attrs.tgListitemSeverity,function(issue){return render($scope.severityById,issue)})},{link:link,template:template}},ListItemTypeDirective=function(){var link,template;return template='
    ',link=function($scope,$el,$attrs){var render;return render=function(issueTypeById,issue){var domNode,type;return type=issueTypeById[issue.type],domNode=$el.find(".level"),domNode.css("background-color",type.color),domNode.attr("title",type.name)},bindOnce($scope,"issueTypeById",function(issueTypeById){var issue;return issue=$scope.$eval($attrs.tgListitemType),render(issueTypeById,issue)}),$scope.$watch($attrs.tgListitemType,function(issue){return render($scope.issueTypeById,issue)})},{link:link,template:template}},TgProgressBarDirective=function(){var link,render,template;return template=_.template('
    '),render=function(el,percentage){return el.html(template({percentage:percentage}))},link=function($scope,$el,$attrs){var element;return element=angular.element($el),$scope.$watch($attrs.tgProgressBar,function(percentage){return percentage=_.max([0,percentage]),percentage=_.min([100,percentage]),render($el,percentage)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},TgMainTitleDirective=function(){var link,render,template;return template=_.template('<%- projectName %>\n<%- sectionName %>'),render=function(el,projectName,sectionName){return el.html(template({projectName:projectName,sectionName:sectionName}))},link=function($scope,$el){var element;return element=angular.element($el),$scope.$watch("project",function(project){return project?render($el,project.name,$scope.sectionName):void 0}),$scope.$on("project:loaded",function(){return function(ctx,project){return render($el,project.name,$scope.sectionName)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgListitemType",ListItemTypeDirective),module.directive("tgListitemIssueStatus",ListItemIssueStatusDirective),module.directive("tgListitemAssignedto",ListItemAssignedtoDirective),module.directive("tgListitemPriority",ListItemPriorityDirective),module.directive("tgListitemSeverity",ListItemSeverityDirective),module.directive("tgListitemTaskStatus",ListItemTaskStatusDirective),module.directive("tgListitemUsStatus",ListItemUsStatusDirective),module.directive("tgProgressBar",TgProgressBarDirective),module.directive("tgMainTitle",TgMainTitleDirective)}.call(this),function(){var ConfirmService,NOTIFICATION_MSG,bindMethods,cancelTimeout,debounce,module,taiga,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,timeout=this.taiga.timeout,cancelTimeout=this.taiga.cancelTimeout,debounce=this.taiga.debounce,bindMethods=this.taiga.bindMethods,NOTIFICATION_MSG={success:{title:"Everything is ok",message:"Our Oompa Loompas saved all your changes!"},error:{title:"Oops, something happened...",message:"Our Oompa Loompas are sad, your changes were not saved!"},"light-error":{title:"Oops, something happened...",message:"Our Oompa Loompas are sad, your changes were not saved!"}},ConfirmService=function(_super){function ConfirmService(q,lightboxService,loading){this.q=q,this.lightboxService=lightboxService,this.loading=loading,bindMethods(this)}return __extends(ConfirmService,_super),ConfirmService.$inject=["$q","lightboxService","$tgLoading"],ConfirmService.prototype.hide=function(el){return el?(this.lightboxService.close(el),el.off(".confirm-dialog")):void 0},ConfirmService.prototype.ask=function(title,subtitle,message,lightboxSelector){var defered,el;return null==lightboxSelector&&(lightboxSelector=".lightbox-generic-ask"),el=angular.element(lightboxSelector),el.find("h2.title").html(title),el.find("span.subtitle").html(subtitle),el.find("span.message").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",debounce(2e3,function(_this){return function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),_this.loading.start(target),defered.resolve(function(ok){return null==ok&&(ok=!0),_this.loading.finish(target),ok?_this.hide(el):void 0})}}(this))),el.on("click.confirm-dialog","a.button-red",function(_this){return function(event){return event.preventDefault(),defered.reject(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.askOnDelete=function(title,message){return this.ask(title,"Are you sure you want to delete?",message)},ConfirmService.prototype.askChoice=function(title,subtitle,choices,replacement,warning,lightboxSelector){var choicesField,defered,el;return null==lightboxSelector&&(lightboxSelector=".lightbox-ask-choice"),el=angular.element(lightboxSelector),el.find(".title").html(title),el.find(".subtitle").html(subtitle),replacement?el.find(".replacement").html(replacement):el.find(".replacement").remove(),warning?el.find(".warning").html(warning):el.find(".warning").remove(),choicesField=el.find(".choices"),choicesField.html(""),_.each(choices,function(value,key){return choicesField.append(angular.element(""))}),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",debounce(2e3,function(_this){return function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),_this.loading.start(target),defered.resolve({selected:choicesField.val(),finish:function(){return _this.loading.finish(target),_this.hide(el)}})}}(this))),el.on("click.confirm-dialog","a.button-red",function(_this){return function(event){return event.preventDefault(),defered.reject(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.error=function(message){var defered,el;return el=angular.element(".lightbox-generic-error"),el.find("h2.title").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),el.on("click.confirm-dialog","a.close",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.success=function(message){var defered,el;return el=angular.element(".lightbox-generic-success"),el.find("h2.title").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),el.on("click.confirm-dialog","a.close",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.notify=function(type,message,title,time){var body,el,selector;return selector=".notification-message-"+type,el=angular.element(selector),el.hasClass("active")?void 0:(el.find("h4").html(title?title:NOTIFICATION_MSG[type].title),el.find("p").html(message?message:NOTIFICATION_MSG[type].message),body=angular.element("body"),body.find(".notification-message .notification-light").removeClass("active").addClass("inactive"),body.find(selector).removeClass("inactive").addClass("active"),this.tsem&&cancelTimeout(this.tsem),time||(time="error"===type||"light-error"===type?3500:1500),this.tsem=timeout(time,function(_this){return function(){return body.find(selector).removeClass("active").addClass("inactive"),delete _this.tsem}}(this)),el.on("click",".icon-delete",function(){return function(){return body.find(selector).removeClass("active").addClass("inactive")}}(this)))},ConfirmService}(taiga.Service),module=angular.module("taigaCommon"),module.service("$tgConfirm",ConfirmService)}.call(this),function(){var LbUsEstimationDirective,UsEstimationDirective,module,taiga;taiga=this.taiga,module=angular.module("taigaCommon"),LbUsEstimationDirective=function(){var link,mainTemplate,pointsTemplate;return mainTemplate=_.template('
      \n
    • \n <%- totalPoints %>\n total\n
    • \n <% _.each(roles, function(role) { %>\n
    • \n <%- role.points %>\n <%- role.name %>
    • \n <% }); %>\n
    '),pointsTemplate=_.template('
    '),link=function($scope,$el,$attrs,$model){var calculateTotalPoints,render,renderPoints;return render=function(points){var computableRoles,ctx,html,roles,totalPoints;return totalPoints=calculateTotalPoints(points)||0,computableRoles=_.filter($scope.project.roles,"computable"),roles=_.map(computableRoles,function(role){var pointId,pointObj;return pointId=points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj&&null!=pointObj.name?pointObj.name:"?",role}),ctx={totalPoints:totalPoints,roles:roles},html=mainTemplate(ctx),$el.html(html)},renderPoints=function(target,usPoints,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=usPoints[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points,roleId:roleId}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").remove(),$el.find(target).append(html),$el.find(".pop-points-open").popover().open(function(){return $(this).removeClass("active")}),$el.find(".pop-points-open").show()},calculateTotalPoints=function(points){var values;return values=_.map(points,function(v){var _ref;return(null!=(_ref=$scope.pointsById[v])?_ref.value:void 0)||0}),0===values.length?"0":_.reduce(values,function(acc,num){return acc+num})},$el.on("click",".total.clickable",function(event){var points,roleId,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),roleId=target.data("role-id"),points=$model.$modelValue,renderPoints(target,points,roleId),target.siblings().removeClass("active"),target.addClass("active")}),$el.on("click",".point",function(event){var pointId,points,roleId,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),roleId=target.data("role-id"),pointId=target.data("point-id"),$el.find(".popover").popover().close(),points=_.clone($model.$modelValue,!0),points[roleId]=pointId,$scope.$apply(function(){return $model.$setViewValue(points)})}),$scope.$watch($attrs.ngModel,function(points){return points?render(points):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgLbUsEstimation",["$rootScope","$tgRepo","$tgConfirm",LbUsEstimationDirective]),UsEstimationDirective=function($rootScope,$repo,$confirm,$qqueue){var link,mainTemplate,pointsTemplate;return mainTemplate=_.template('
      \n
    • \n <%- totalPoints %>\n total\n
    • \n <% _.each(roles, function(role) { %>\n
    • \n <%- role.points %>\n <%- role.name %>
    • \n <% }); %>\n
    '),pointsTemplate=_.template(''),link=function($scope,$el,$attrs,$model){var calculateTotalPoints,isEditable,render,renderPoints,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var computableRoles,ctx,html,roles,totalPoints;return totalPoints=null!=us.total_points?us.total_points:"?",computableRoles=_.filter($scope.project.roles,"computable"),roles=_.map(computableRoles,function(role){var pointId,pointObj;return pointId=us.points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj&&null!=pointObj.name?pointObj.name:"?",role}),ctx={totalPoints:totalPoints,roles:roles,editable:isEditable()},html=mainTemplate(ctx),$el.html(html)},renderPoints=function(target,us,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=us.points[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points,roleId:roleId}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").remove(),$el.find(target).append(html),$el.find(".pop-points-open").popover().open(function(){return $(this).removeClass("active").closest("li").removeClass("active") -}),$el.find(".pop-points-open").show()},calculateTotalPoints=function(us){var notNullValues,values;return values=_.map(us.points,function(v){var _ref;return null!=(_ref=$scope.pointsById[v])?_ref.value:void 0}),0===values.length?"0":(notNullValues=_.filter(values,function(v){return null!=v}),0===notNullValues.length?"?":_.reduce(notNullValues,function(acc,num){return acc+num}))},save=$qqueue.bindAdd(function(){return function(roleId,pointId){var onError,onSuccess,points,us;return $el.find(".popover").popover().close(),us=angular.copy($model.$modelValue),points=_.clone($model.$modelValue.points,!0),points[roleId]=pointId,us.setAttr("points",points),us.points=points,us.total_points=calculateTotalPoints(us),$model.$setViewValue(us),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),us.revert(),$model.$setViewValue(us)},$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".total.clickable",function(event){var roleId,target,us;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),roleId=target.data("role-id"),us=$model.$modelValue,renderPoints(target,us,roleId),target.siblings().removeClass("active"),target.addClass("active")):void 0}),$el.on("click",".point",function(event){var pointId,roleId,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),roleId=target.data("role-id"),pointId=target.data("point-id"),save(roleId,pointId)):void 0}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsEstimation",["$rootScope","$tgRepo","$tgConfirm","$tgQqueue",UsEstimationDirective])}.call(this),function(){var defaultFilter,module,momentFormat,momentFromNow,taiga,unslugify,yesNoFilter;taiga=this.taiga,module=angular.module("taigaCommon"),defaultFilter=function(){return function(value,defaultValue){return value===[null,void 0]?defaultValue:value}},module.filter("default",defaultFilter),yesNoFilter=function(){return function(value){return value?"Yes":"No"}},module.filter("yesNo",yesNoFilter),unslugify=function(){return taiga.unslugify},module.filter("unslugify",unslugify),momentFormat=function(){return function(input,format){return input?moment(input).format(format):""}},module.filter("momentFormat",momentFormat),momentFromNow=function(){return function(input,without_suffix){return input?moment(input).fromNow(without_suffix||!1):""}},module.filter("momentFromNow",momentFromNow)}.call(this),function(){var HistoryController,HistoryDirective,bindOnce,debounce,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaCommon"),HistoryController=function(_super){function HistoryController(scope,repo,rs){this.scope=scope,this.repo=repo,this.rs=rs}return __extends(HistoryController,_super),HistoryController.$inject=["$scope","$tgRepo","$tgResources"],HistoryController.prototype.initialize=function(type,objectId){return this.type=type,this.objectId=objectId},HistoryController.prototype.loadHistory=function(type,objectId){return this.rs.history.get(type,objectId).then(function(_this){return function(history){var historyResult,_i,_len;for(_i=0,_len=history.length;_len>_i;_i++)historyResult=history[_i],null!=historyResult.values_diff.description_diff&&(historyResult.values_diff.description=historyResult.values_diff.description_diff),delete historyResult.values_diff.description_html,delete historyResult.values_diff.description_diff;return _this.scope.history=history,_this.scope.comments=_.filter(history,function(item){return""!==item.comment})}}(this))},HistoryController.prototype.deleteComment=function(type,objectId,activityId){return this.rs.history.deleteComment(type,objectId,activityId).then(function(_this){return function(){return _this.loadHistory(type,objectId)}}(this))},HistoryController.prototype.undeleteComment=function(type,objectId,activityId){return this.rs.history.undeleteComment(type,objectId,activityId).then(function(_this){return function(){return _this.loadHistory(type,objectId)}}(this))},HistoryController}(taiga.Controller),HistoryDirective=function($log,$loading,$qqueue){var link,templateActivity,templateBase,templateBaseEntries,templateChangeAttachment,templateChangeDiff,templateChangeGeneric,templateChangePoints,templateDeletedComment,templateFn;return templateChangeDiff=_.template('
    \n
    \n <%- name %>\n
    \n
    \n

    \n <%= diff %>\n

    \n
    \n
    '),templateChangePoints=_.template('<% _.each(points, function(point, name) { %>\n
    \n
    \n US points (<%- name.toLowerCase() %>)\n
    \n
    \n

    \n from
    \n <%- point[0] %>\n

    \n

    \n to
    \n <%- point[1] %>\n

    \n
    \n
    \n<% }); %>'),templateChangeGeneric=_.template('
    \n
    \n <%- name %>\n
    \n
    \n

    \n from
    \n <%- from %>\n

    \n

    \n to
    \n <%- to %>\n

    \n
    \n
    '),templateChangeAttachment=_.template('
    \n
    \n <%- name %>\n
    \n
    \n <% _.each(diff, function(change) { %>\n

    \n <%- change.name %> from
    \n <%- change.from %>\n

    \n

    \n <%- change.name %> to
    \n <%- change.to %>\n

    \n <% }) %>\n
    \n
    '),templateDeletedComment=_.template('
    \n
    \n Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>\n (Show deleted comment)\n \n
    <%= deleteComment %>
    \n
    \n <% if (canRestoreComment) { %>\n \n \n Restore comment\n \n <% } %>\n
    '),templateActivity=_.template('
    \n
    \n \n <%- userFullName %>\n \n
    \n
    \n
    \n \n <%- userFullName %>\n \n \n <%- creationDate %>\n \n
    \n\n <% if (comment.length > 0) { %>\n <% if ((deleteCommentDate || deleteCommentUser)) { %>\n
    \n Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>\n
    \n <% } %>\n
    \n <%= comment %>\n
    \n <% if (!deleteCommentDate && mode !== "activity" && canDeleteComment) { %>\n \n <% } %>\n <% } %>\n\n <% if(changes.length > 0) { %>\n
    \n <% if (mode != "activity") { %>\n \n <%- changesText %>\n \n \n <% } %>\n\n <% _.each(changes, function(change) { %>\n <%= change %>\n <% }) %>\n
    \n <% } %>\n
    \n
    '),templateBaseEntries=_.template('\n<% if (showMore > 0) { %>\n\n+ Show previous entries (<%- showMore %> more)\n\n<% } %>\n<% _.each(entries, function(entry) { %>\n <%= entry %>\n<% }) %>'),templateBase=_.template('
    \n \n
    \n
    \n
    \n \n <% if (mode !== "edit") { %>\n \n \n Markdown syntax help\n \n Comment\n <% } %>\n
    \n
    \n \n
    '),link=function($scope,$el,$attrs,$ctrl){var countChanges,formatChange,getHumanizedFieldName,getUserAvatar,getUserFullName,objectId,renderActivity,renderAttachmentEntry,renderChange,renderChangeEntries,renderChangeEntry,renderChangesHelperText,renderComment,renderComments,renderHistory,save,showAllActivity,showAllComments,type;return type=$attrs.type,objectId=null,showAllComments=!1,showAllActivity=!1,bindOnce($scope,$attrs.ngModel,function(model){return type=$attrs.type,objectId=model.id,$ctrl.initialize(type,objectId),$ctrl.loadHistory(type,objectId)}),getHumanizedFieldName=function(field){var humanizedFieldNames;return humanizedFieldNames={assigned_to:"assigned to",is_closed:"is closed",finish_date:"finish date",client_requirement:"client requirement",team_requirement:"team requirement",milestone:"sprint",user_story:"user story",is_iocaine:"is iocaine",is_deprecated:"is deprecated"},humanizedFieldNames[field]||field},getUserFullName=function(userId){var _ref;return null!=(_ref=$scope.usersById[userId])?_ref.full_name_display:void 0},getUserAvatar=function(userId){return null!=$scope.usersById[userId]?$scope.usersById[userId].photo:"/images/unnamed.png"},countChanges=function(comment){return _.keys(comment.values_diff).length},formatChange=function(change){return _.isArray(change)?0===change.length?"nil":change.join(", "):""===change?"nil":change===!0?"yes":change===!1?"no":change},renderAttachmentEntry=function(value){var attachments;return attachments=_.map(value,function(changes,type){return"new"===type?_.map(changes,function(change){return templateChangeDiff({name:"new attachment",diff:change.filename})}):"deleted"===type?_.map(changes,function(change){return templateChangeDiff({name:"deleted attachment",diff:change.filename})}):_.map(changes,function(change){var diff,name;return name="updated attachment "+change.filename,diff=_.map(change.changes,function(values,name){return{name:getHumanizedFieldName(name),from:formatChange(values[0]),to:formatChange(values[1])}}),templateChangeAttachment({name:name,diff:diff})})}),_.flatten(attachments).join("\n")},renderChangeEntry=function(field,value){var from,name,to;return"description"===field?templateChangeDiff({name:"description",diff:value[1]}):"points"===field?templateChangePoints({points:value}):"attachments"===field?renderAttachmentEntry(value):"assigned_to"===field?(name=getHumanizedFieldName(field),from=formatChange(value[0]||"Unassigned"),to=formatChange(value[1]||"Unassigned"),templateChangeGeneric({name:name,from:from,to:to})):(name=getHumanizedFieldName(field),from=formatChange(value[0]),to=formatChange(value[1]),templateChangeGeneric({name:name,from:from,to:to}))},renderChangeEntries=function(change,join){var entries;return null==join&&(join=!0),entries=_.map(change.values_diff,function(value,field){return renderChangeEntry(field,value)}),join?entries.join("\n"):entries},renderChangesHelperText=function(change){var size;return size=countChanges(change),1===size?"Made "+size+" change":"Made "+size+" changes"},renderComment=function(comment){var _ref;return comment.delete_comment_date||comment.delete_comment_user?templateDeletedComment({deleteCommentDate:moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm"),deleteCommentUser:comment.delete_comment_user.name,deleteComment:comment.comment_html,activityId:comment.id,canRestoreComment:comment.delete_comment_user.pk===$scope.user.id||$scope.project.my_permissions.indexOf("modify_project")>-1}):templateActivity({avatar:getUserAvatar(comment.user.pk),userFullName:comment.user.name,creationDate:moment(comment.created_at).format("DD MMM YYYY HH:mm"),comment:comment.comment_html,changesText:renderChangesHelperText(comment),changes:renderChangeEntries(comment,!1),mode:"comment",deleteCommentDate:comment.delete_comment_date?moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm"):void 0,deleteCommentUser:(null!=(_ref=comment.delete_comment_user)?_ref.name:void 0)?comment.delete_comment_user.name:void 0,activityId:comment.id,canDeleteComment:comment.user.pk===$scope.user.id||$scope.project.my_permissions.indexOf("modify_project")>-1})},renderChange=function(change){var _ref;return templateActivity({avatar:getUserAvatar(change.user.pk),userFullName:change.user.name,creationDate:moment(change.created_at).format("DD MMM YYYY HH:mm"),comment:change.comment_html,changes:renderChangeEntries(change,!1),changesText:"",mode:"activity",deleteCommentDate:change.delete_comment_date?moment(change.delete_comment_date).format("DD MMM YYYY HH:mm"):void 0,deleteCommentUser:(null!=(_ref=change.delete_comment_user)?_ref.name:void 0)?change.delete_comment_user.name:void 0,activityId:change.id})},renderHistory=function(entries,totalEntries){var showMore;return showMore=entries.length===totalEntries?0:totalEntries-entries.length,templateBaseEntries({entries:entries,showMore:showMore})},renderComments=function(){var comments,html,totalComments;return comments=$scope.comments||[],totalComments=comments.length,showAllComments||(comments=_.last(comments,4)),comments=_.map(comments,function(x){return renderComment(x)}),html=renderHistory(comments,totalComments),$el.find(".comments-list").html(html)},renderActivity=function(){var changes,html,totalChanges;return changes=$scope.history||[],totalChanges=changes.length,showAllActivity||(changes=_.last(changes,4)),changes=_.map(changes,function(x){return renderChange(x)}),html=renderHistory(changes,totalChanges),$el.find(".changes-list").html(html)},save=$qqueue.bindAdd(function(){return function(target){var model,onError,onSuccess;return $scope.$broadcast("markdown-editor:submit"),$el.find(".comment-list").addClass("activeanimation"),onSuccess=function(){return $ctrl.loadHistory(type,objectId)["finally"](function(){return $loading.finish(target)})},onError=function(){return $loading.finish(target),$confirm.notify("error")},model=$scope.$eval($attrs.ngModel),$loading.start(target),$ctrl.repo.save(model).then(onSuccess,onError)}}(this)),$scope.$watch("comments",renderComments),$scope.$watch("history",renderActivity),$scope.$on("history:reload",function(){return $ctrl.loadHistory(type,objectId)}),$el.on("click",".add-comment a.button-green",debounce(2e3,function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),save(target)})),$el.on("click",".show-more",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parent().is(".changes-list")?(showAllActivity=!showAllActivity,renderActivity()):(showAllComments=!showAllComments,renderComments())}),$el.on("click",".show-deleted-comment",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parents(".activity-single").find(".hide-deleted-comment").show(),target.parents(".activity-single").find(".show-deleted-comment").hide(),target.parents(".activity-single").find(".comment-body").show()}),$el.on("click",".hide-deleted-comment",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parents(".activity-single").find(".hide-deleted-comment").hide(),target.parents(".activity-single").find(".show-deleted-comment").show(),target.parents(".activity-single").find(".comment-body").hide()}),$el.on("click",".changes-title",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parent().find(".change-entry").toggleClass("active")}),$el.on("focus",".add-comment textarea",function(){return $(this).addClass("active")}),$el.on("click",".history-tabs li a",function(){return $el.find(".history-tabs li a").toggleClass("active"),$el.find(".history section").toggleClass("hidden")}),$el.on("click",".comment-delete",debounce(2e3,function(event){var activityId,target;return target=angular.element(event.currentTarget),activityId=target.data("activity-id"),$ctrl.deleteComment(type,objectId,activityId)})),$el.on("click",".comment-restore",debounce(2e3,function(event){var activityId,target;return target=angular.element(event.currentTarget),activityId=target.data("activity-id"),$ctrl.undeleteComment(type,objectId,activityId)})),$scope.$on("$destroy",function(){return $el.off()})},templateFn=function($el,$attrs){return templateBase({ngmodel:$attrs.ngModel,type:$attrs.type,mode:$attrs.mode})},{controller:HistoryController,template:templateFn,restrict:"AE",link:link}},module.directive("tgHistory",["$log","$tgLoading","$tgQqueue",HistoryDirective])}.call(this),function(){var AssignedToLightboxDirective,BlockLightboxDirective,BlockingMessageInputDirective,CreateBulkUserstoriesDirective,CreateEditUserstoryDirective,LightboxDirective,LightboxKeyboardNavigationService,LightboxService,NotionButtonDirective,NotionLightboxDirective,WatchersLightboxDirective,bindOnce,debounce,module,timeout,usersTemplate,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};module=angular.module("taigaCommon"),bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,debounce=this.taiga.debounce,LightboxService=function(_super){function LightboxService(animationFrame){this.animationFrame=animationFrame}return __extends(LightboxService,_super),LightboxService.prototype.open=function($el){var docEl,lightboxContent;return lightboxContent=$el.children().not(".close"),lightboxContent.hide(),$el.css("display","flex"),$el.find("input,textarea").first().focus(),this.animationFrame.add(function(){return function(){return $el.addClass("open"),lightboxContent.show()}}(this)),docEl=angular.element(document),docEl.on("keydown.lightbox",function(_this){return function(e){var code;return code=e.keyCode?e.keyCode:e.which,27===code?_this.close($el):void 0}}(this))},LightboxService.prototype.close=function($el){var docEl;return docEl=angular.element(document),docEl.off(".lightbox"),docEl.off(".keyboard-navigation"),$el.one("transitionend",function(){return function(){return $el.removeAttr("style"),$el.removeClass("open").removeClass("close")}}(this)),$el.addClass("close")},LightboxService.prototype.closeAll=function(){var docEl,lightboxEl,_i,_len,_ref,_results;for(docEl=angular.element(document),_ref=docEl.find(".lightbox.open"),_results=[],_i=0,_len=_ref.length;_len>_i;_i++)lightboxEl=_ref[_i],_results.push(this.close($(lightboxEl)));return _results},LightboxService}(taiga.Service),module.service("lightboxService",["animationFrame",LightboxService]),LightboxKeyboardNavigationService=function(_super){function LightboxKeyboardNavigationService(){return LightboxKeyboardNavigationService.__super__.constructor.apply(this,arguments)}return __extends(LightboxKeyboardNavigationService,_super),LightboxKeyboardNavigationService.prototype.stop=function(){var docEl;return docEl=angular.element(document),docEl.off(".keyboard-navigation")},LightboxKeyboardNavigationService.prototype.dispatch=function($el,code){var activeElement,next,prev;if(activeElement=$el.find(".active"),13===code)return activeElement.trigger("click");if(40===code){if(!activeElement.length)return $el.find(".watcher-single:first").addClass("active");if(next=activeElement.next(".watcher-single"),next.length)return activeElement.removeClass("active"),next.addClass("active")}else if(38===code){if(!activeElement.length)return $el.find(".watcher-single:last").addClass("active");if(prev=activeElement.prev(".watcher-single"),prev.length)return activeElement.removeClass("active"),prev.addClass("active")}},LightboxKeyboardNavigationService.prototype.init=function($el){var docEl;return this.stop(),docEl=angular.element(document),docEl.on("keydown.keyboard-navigation",function(_this){return function(event){var code;return code=event.keyCode?event.keyCode:event.which,40===code||38===code||13===code?(event.preventDefault(),_this.dispatch($el,code)):void 0}}(this))},LightboxKeyboardNavigationService}(taiga.Service),module.service("lightboxKeyboardNavigationService",LightboxKeyboardNavigationService),LightboxDirective=function(lightboxService){var link;return link=function($scope,$el){return $el.on("click",".close",function(event){return event.preventDefault(),lightboxService.close($el)})},{restrict:"C",link:link}},module.directive("lightbox",["lightboxService",LightboxDirective]),BlockLightboxDirective=function($rootscope,$tgrepo,$confirm,lightboxService,$loading,$qqueue){var link;return link=function($scope,$el,$attrs,$model){var block,unblock;return $el.find("h2.title").text($attrs.title),unblock=$qqueue.bindAdd(function(){return function(item,finishCallback){var promise;return promise=$tgrepo.save(item),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$model.$setViewValue(item),finishCallback()}),promise.then(null,function(){return $confirm.notify("error"),item.revert(),$model.$setViewValue(item)}),promise["finally"](function(){return finishCallback()}),promise}}(this)),block=$qqueue.bindAdd(function(){return function(item){var promise;return $model.$setViewValue(item),$loading.start($el.find(".button-green")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $confirm.notify("error"),item.revert(),$model.$setViewValue(item)}),promise["finally"](function(){return $loading.finish($el.find(".button-green")),lightboxService.close($el)})}}(this)),$scope.$on("block",function(){return $el.find(".reason").val($model.$modelValue.blocked_note),lightboxService.open($el)}),$scope.$on("unblock",function(){return function(event,model,finishCallback){var item;return item=$model.$modelValue.clone(),item.is_blocked=!1,item.blocked_note="",unblock(item,finishCallback)}}(this)),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click",".button-green",function(event){var item;return event.preventDefault(),item=$model.$modelValue.clone(),item.is_blocked=!0,item.blocked_note=$el.find(".reason").val(),block(item)})},{templateUrl:"/partials/views/modules/lightbox-block.html",link:link,require:"ngModel"}},module.directive("tgLbBlock",["$rootScope","$tgRepo","$tgConfirm","lightboxService","$tgLoading","$tgQqueue",BlockLightboxDirective]),BlockingMessageInputDirective=function($log){var link,template,templateFn;return template=_.template(''),link=function($scope,$el,$attrs){return $attrs.watch?$scope.$watch($attrs.watch,function(value){return value===!0&&value===!0?$el.find(".blocked-note").removeClass("hidden"):$el.find(".blocked-note").addClass("hidden")}):$log.error("No watch attribute on tg-blocking-message-input directive")},templateFn=function($el,$attrs){return template({ngmodel:$attrs.ngModel})},{template:templateFn,link:link,require:"ngModel",restrict:"EA"}},module.directive("tgBlockingMessageInput",["$log",BlockingMessageInputDirective]),CreateEditUserstoryDirective=function($repo,$model,$rs,$rootScope,lightboxService,$loading){var link;return link=function($scope,$el){var submit,submitButton;return $scope.isNew=!0,$scope.$on("usform:new",function(ctx,projectId,status,statusList){return $scope.isNew=!0,$scope.usStatusList=statusList,$scope.us=$model.make_model("userstories",{project:projectId,points:{},status:status,is_archived:!1,tags:[]}),$el.find(".button-green").html("Create"),$el.find(".title").html("New user story "),$el.find(".tag-input").val(""),$el.find(".blocked-note").addClass("hidden"),$el.find("label.blocked").removeClass("selected"),$el.find("label.team-requirement").removeClass("selected"),$el.find("label.client-requirement").removeClass("selected"),lightboxService.open($el)}),$scope.$on("usform:edit",function(ctx,us){return $scope.us=us,$scope.isNew=!1,$el.find(".button-green").html("Save"),$el.find(".title").html("Edit user story "),$el.find(".tag-input").val(""),us.is_blocked?($el.find(".blocked-note").removeClass("hidden"),$el.find("label.blocked").addClass("selected")):($el.find(".blocked-note").addClass("hidden"),$el.find("label.blocked").removeClass("selected")),us.team_requirement?$el.find("label.team-requirement").addClass("selected"):$el.find("label.team-requirement").removeClass("selected"),us.client_requirement?$el.find("label.client-requirement").addClass("selected"):$el.find("label.client-requirement").removeClass("selected"),lightboxService.open($el)}),submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),$scope.isNew?(promise=$repo.create("userstories",$scope.us),broadcastEvent="usform:new:success"):(promise=$repo.save($scope.us),broadcastEvent="usform:edit:success"),promise.then(function(data){return $loading.finish(submitButton),lightboxService.close($el),$rootScope.$broadcast(broadcastEvent,data)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".close",function(event){return event.preventDefault(),$scope.$apply(function(){return $scope.us.revert()}),lightboxService.close($el)}),$el.keydown(function(event){var code;return code=event.keyCode?event.keyCode:event.which,27===code?(lightboxService.close($el),$scope.$apply(function(){return $scope.us.revert()})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateEditUserstory",["$tgRepo","$tgModel","$tgResources","$rootScope","lightboxService","$tgLoading",CreateEditUserstoryDirective]),CreateBulkUserstoriesDirective=function($repo,$rs,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var submit,submitButton;return $scope.$on("usform:bulk",function(ctx,projectId,status){return $scope["new"]={projectId:projectId,statusId:status,bulk:""},lightboxService.open($el)}),submit=debounce(2e3,function(){return function(event){var form,promise;return event.preventDefault(),form=$el.find("form").checksley({onlyOneErrorElement:!0}),form.validate()?($loading.start(submitButton),promise=$rs.userstories.bulkCreate($scope["new"].projectId,$scope["new"].statusId,$scope["new"].bulk),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("usform:bulk:success",result),lightboxService.close($el)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateBulkUserstories",["$tgRepo","$tgResources","$rootScope","lightboxService","$tgLoading",CreateBulkUserstoriesDirective]),usersTemplate=_.template('<% if (selected) { %>\n\n<% } %>\n\n<% _.each(users, function(user) { %>\n\n<% }) %>\n\n<% if (showMore) { %>\n
    \n ...too many users, keep filtering\n
    \n<% } %>'),AssignedToLightboxDirective=function(lightboxService,lightboxKeyboardNavigationService){var link;return link=function($scope,$el){var closeLightbox,filterUsers,normalizeString,render,selectedItem,selectedUser;return selectedUser=null,selectedItem=null,normalizeString=function(string){var normalizedString;return normalizedString=string,normalizedString=normalizedString.replace("Á","A").replace("Ä","A").replace("À","A"),normalizedString=normalizedString.replace("É","E").replace("Ë","E").replace("È","E"),normalizedString=normalizedString.replace("Í","I").replace("Ï","I").replace("Ì","I"),normalizedString=normalizedString.replace("Ó","O").replace("Ö","O").replace("Ò","O"),normalizedString=normalizedString.replace("Ú","U").replace("Ü","U").replace("Ù","U")},filterUsers=function(text,user){var username;return username=user.full_name_display.toUpperCase(),username=normalizeString(username),text=text.toUpperCase(),text=normalizeString(text),_.contains(username,text) -},render=function(selected,text){var ctx,html,users;return $el.find("input").focus(),users=_.clone($scope.activeUsers,!0),null!=selected&&(users=_.reject(users,{id:selected.id})),null!=text&&(users=_.filter(users,_.partial(filterUsers,text))),ctx={selected:selected,users:_.first(users,5),showMore:users.length>5},html=usersTemplate(ctx),$el.find("div.watchers").html(html),lightboxKeyboardNavigationService.init($el)},closeLightbox=function(){return lightboxKeyboardNavigationService.stop(),lightboxService.close($el)},$scope.$on("assigned-to:add",function(ctx,item){var assignedToId;return selectedItem=item,assignedToId=item.assigned_to,selectedUser=$scope.usersById[assignedToId],render(selectedUser),lightboxService.open($el),$el.find("input").focus()}),$scope.$watch("usersSearch",function(searchingText){return null!=searchingText?render(selectedUser,searchingText):void 0}),$el.on("click",".watcher-single",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),closeLightbox(),$scope.$apply(function(){return $scope.$broadcast("assigned-to:added",target.data("user-id"),selectedItem),$scope.usersSearch=null})}),$el.on("click",".remove-assigned-to",function(event){return event.preventDefault(),event.stopPropagation(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null,$scope.$broadcast("assigned-to:added",null,selectedItem)})}),$el.on("click",".close",function(event){return event.preventDefault(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"/partials/views/modules/lightbox-assigned-to.html",link:link}},module.directive("tgLbAssignedto",["lightboxService","lightboxKeyboardNavigationService",AssignedToLightboxDirective]),WatchersLightboxDirective=function($repo,lightboxService,lightboxKeyboardNavigationService){var link;return link=function($scope,$el){var closeLightbox,getFilteredUsers,render,selectedItem;return selectedItem=null,getFilteredUsers=function(text){var users,_filterUsers;return null==text&&(text=""),_filterUsers=function(text,user){var username;return selectedItem&&_.find(selectedItem.watchers,function(x){return x===user.id})?!1:(username=user.full_name_display.toUpperCase(),text=text.toUpperCase(),_.contains(username,text))},users=_.clone($scope.activeUsers,!0),users=_.filter(users,_.partial(_filterUsers,text))},render=function(users){var ctx,html;return $el.find("input").focus(),ctx={selected:!1,users:_.first(users,5),showMore:users.length>5},html=usersTemplate(ctx),$el.find("div.watchers").html(html)},closeLightbox=function(){return lightboxKeyboardNavigationService.stop(),lightboxService.close($el)},$scope.$on("watcher:add",function(ctx,item){var users;return selectedItem=item,users=getFilteredUsers(),render(users),lightboxService.open($el),lightboxKeyboardNavigationService.init($el)}),$scope.$watch("usersSearch",function(searchingText){var users;if(null!=searchingText)return users=getFilteredUsers(searchingText),render(users)}),$el.on("click",".watcher-single",debounce(2e3,function(event){var target;return closeLightbox(),event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $scope.usersSearch=null,$scope.$broadcast("watcher:added",target.data("user-id"))})})),$el.on("click",".close",function(event){return event.preventDefault(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"/partials/views/modules/lightbox-users.html",link:link}},module.directive("tgLbWatchers",["$tgRepo","lightboxService","lightboxKeyboardNavigationService",WatchersLightboxDirective]),NotionLightboxDirective=function(lightboxService){var link;return link=function($scope,$el){return $scope.$on("notion:open",function(event,lightboxId){return $el.attr("id")===lightboxId?lightboxService.open($el):void 0}),$el.on("click",".button-green",function(){return lightboxService.close($el)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbNotion",["lightboxService",NotionLightboxDirective]),NotionButtonDirective=function($log,$rootScope){var link;return link=function($scope,$el,$attrs){return null==$attrs.tgLbNotionButton?$log.error("NotionButtonDirective: the directive need the id of the notion lightbox"):($el.on("click",function(){return $rootScope.$broadcast("notion:open",$attrs.tgLbNotionButton)}),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgLbNotionButton",["$log","$rootScope",NotionButtonDirective])}.call(this),function(){var Loader,LoaderDirective,module,sizeFormat,taiga,timeout;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,timeout=this.taiga.timeout,module=angular.module("taigaCommon"),LoaderDirective=function(tgLoader,$rootscope){var link;return link=function($scope,$el){return tgLoader.onStart(function(){return $(document.body).addClass("loader-active"),$el.addClass("active")}),tgLoader.onEnd(function(){return $(document.body).removeClass("loader-active"),$el.removeClass("active")}),$rootscope.$on("$routeChangeSuccess",function(){return tgLoader.startCurrentPageLoader()}),$rootscope.$on("$locationChangeSuccess",function(){return tgLoader.reset()})},{link:link}},module.directive("tgLoader",["tgLoader","$rootScope",LoaderDirective]),Loader=function(){var config,defaultConfig,forceDisabled;forceDisabled=!1,defaultConfig={enabled:!1,minTime:300},config=_.merge({},defaultConfig),this.add=function(){return function(){return forceDisabled?void 0:config.enabled=!0}},this.$get=["$rootScope",function($rootscope){var pageLoaded,reset,start,startLoadTime;return startLoadTime=0,reset=function(){return config=_.merge({},defaultConfig)},pageLoaded=function(force){var diff,endTime,timeoutValue;return null==force&&(force=!1),startLoadTime?(timeoutValue=0,force||(endTime=(new Date).getTime(),diff=endTime-startLoadTime,diff"))},TgLoadingService.prototype.finish=function(target){var oldContent;return target.hasClass("loading")?(oldContent=target.data("loading-old-content"),target.data("loading-old-content",null),target.html(oldContent),target.removeClass("loading")):void 0},TgLoadingService}(taiga.Service),module.service("$tgLoading",TgLoadingService)}.call(this),function(){var RelatedTaskStatusDirective,UsStatusDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaCommon"),UsStatusDirective=function($repo){var link,template;return template=_.template(''),link=function($scope,$el,$attrs){var $ctrl,render,us;return $ctrl=$el.controller(),render=function(us){var usStatusById,usStatusDom,usStatusDomParent;return usStatusDomParent=$el.find(".us-status"),usStatusDom=$el.find(".us-status .us-status-bind"),usStatusById=$scope.usStatusById,usStatusById[us.status]?(usStatusDom.text(usStatusById[us.status].name),usStatusDomParent.css("color",usStatusById[us.status].color)):void 0},$el.on("click",".us-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",debounce(2e3,function(event){var target,us;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),us=$scope.$eval($attrs.tgUsStatus),us.status=target.data("status-id"),render(us),$el.find(".pop-status").popover().close(),$scope.$apply(function(){return $repo.save(us).then(function(){return $scope.$eval($attrs.onUpdate)})})})),$scope.$on("userstories:loaded",function(){return render($scope.$eval($attrs.tgUsStatus))}),$scope.$on("$destroy",function(){return $el.off()}),us=$scope.$eval($attrs.tgUsStatus),render(us),bindOnce($scope,"project",function(project){var html;return html=template({statuses:project.us_statuses}),$el.append(html),-1===$scope.project.my_permissions.indexOf("modify_us")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0})},{link:link}},module.directive("tgUsStatus",["$tgRepo",UsStatusDirective]),RelatedTaskStatusDirective=function($repo){var link,selectionTemplate,updateTaskStatus;return selectionTemplate=_.template(''),updateTaskStatus=function($el,task,taskStatusById){var taskStatusDom,taskStatusDomParent;return taskStatusDomParent=$el.find(".us-status"),taskStatusDom=$el.find(".task-status .task-status-bind"),taskStatusById[task.status]?(taskStatusDom.text(taskStatusById[task.status].name),taskStatusDomParent.css("color",taskStatusById[task.status].color)):void 0},link=function($scope,$el,$attrs){var $ctrl,autoSave,notAutoSave,task;return $ctrl=$el.controller(),task=$scope.$eval($attrs.tgRelatedTaskStatus),notAutoSave=$scope.$eval($attrs.notAutoSave),autoSave=!notAutoSave,$el.on("click",".task-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",debounce(2e3,function(event){var target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),task.status=target.data("status-id"),$el.find(".pop-status").popover().close(),updateTaskStatus($el,task,$scope.taskStatusById),autoSave?$scope.$apply(function(){return $repo.save(task).then(function(){return $scope.$eval($attrs.onUpdate),$scope.$emit("related-tasks:status-changed")})}):void 0})),taiga.bindOnce($scope,"project",function(project){return $el.append(selectionTemplate({statuses:project.task_statuses})),updateTaskStatus($el,task,$scope.taskStatusById),-1===project.my_permissions.indexOf("modify_task")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskStatus",["$tgRepo",RelatedTaskStatusDirective]),$.fn.popover=function(){var $el,close,closeAll,closePopover,isVisible,open;return $el=this,isVisible=function(){return function(){var docViewBottom,docViewLeft,docViewRight,docViewTop,docViewWidth,elemBottom,elemLeft,elemRight,elemTop,elemWidth;return $el.css({display:"block",visibility:"hidden"}),docViewTop=$(window).scrollTop(),docViewBottom=docViewTop+$(window).height(),docViewWidth=$(window).width(),docViewRight=docViewWidth,docViewLeft=0,elemTop=$el.offset().top,elemBottom=elemTop+$el.height(),elemWidth=$el.width(),elemLeft=$el.offset().left,elemRight=$el.offset().left+elemWidth,$el.css({display:"none",visibility:"visible"}),docViewBottom>=elemBottom&&elemTop>=docViewTop&&elemLeft>=docViewLeft&&docViewRight>=elemRight}}(this),closePopover=function(){return function(onClose){return onClose&&onClose.call($el),$el.fadeOut(function(){return $el.removeClass("active").removeClass("fix")}),$el.off("popup:close")}}(this),closeAll=function(){return function(){return $(".popover.active").each(function(){return $(this).trigger("popup:close")})}}(this),open=function(){return function(onClose){return $el.hasClass("active")?close():(closeAll(),isVisible()||$el.addClass("fix"),$el.fadeIn(function(){return $el.addClass("active"),$(document.body).off("popover"),$(document.body).one("click.popover",function(){return closeAll()})}),$el.on("popup:close",function(){return closePopover(onClose)}))}}(this),close=function(){return function(){return $el.trigger("popup:close")}}(this),{open:open,close:close,closeAll:closeAll}}}.call(this),function(){var ExceptionHandlerFactory,module,taiga;taiga=this.taiga,module=angular.module("taigaCommon"),ExceptionHandlerFactory=function($log,config){var ravenConfig;return this.config=config,ravenConfig=this.config.get("ravenConfig",null),ravenConfig?($log.debug("Using the RavenJS exception handler."),Raven.config(ravenConfig).install(),function(exception){return $log.error.apply($log,arguments),Raven.captureException(exception)}):($log.debug("Using the default logging exception handler."),function(){return $log.error.apply($log,arguments)})},module.factory("$exceptionHandler",["$log","$tgConfig",ExceptionHandlerFactory])}.call(this),function(){var ColorizeTagsDirective,LbTagLineDirective,TagLineDirective,TagsDirective,bindOnce,module,taiga,trim,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),TagsDirective=function(){var formatter,link,parser;return formatter=function(v){return _.isArray(v)?v.join(", "):""},parser=function(v){var result;return v?(result=_(v.split(",")).map(function(x){return _.str.trim(x)}),result.value()):[]},link=function($scope,$el,$attrs,$ctrl){return $ctrl.$formatters.push(formatter),$ctrl.$parsers.push(parser),$scope.$on("$destroy",function(){return $el.off()})},{require:"ngModel",link:link}},module.directive("tgTags",TagsDirective),ColorizeTagsDirective=function(){var link,templates;return templates={backlog:_.template('<% _.each(tags, function(tag) { %>\n <%- tag.name %>\n<% }) %>'),kanban:_.template('<% _.each(tags, function(tag) { %>\n \n<% }) %>'),taskboard:_.template('<% _.each(tags, function(tag) { %>\n \n<% }) %>')},link=function($scope,$el,$attrs){var render;return render=function(srcTags){var html,tags,template;return template=templates[$attrs.tgColorizeTagsType],srcTags.sort(),tags=_.map(srcTags,function(tag){var color;return color=$scope.project.tags_colors[tag],{name:tag,color:color}}),html=template({tags:tags}),$el.html(html)},$scope.$watch($attrs.tgColorizeTags,function(tags){return null!=tags?render(tags):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgColorizeTags",ColorizeTagsDirective),LbTagLineDirective=function(){var COMMA_KEY,ENTER_KEY,link,template,templateTags;return ENTER_KEY=13,COMMA_KEY=188,template='
    \n\n
    ',templateTags=_.template('<% _.each(tags, function(tag) { %>\n style="border-left: 5px solid <%- tag.color %>;"<% } %>>\n <%- tag.name %>\n \n \n<% }); %>'),link=function($scope,$el,$attrs,$model){var addValue,deleteValue,hideSaveButton,removeInputLastCharacter,renderTags,resetInput,saveInputTag,showSaveButton;return renderTags=function(tags,tagsColors){var ctx,html;return ctx={tags:_.map(tags,function(t){return{name:t,color:tagsColors[t]}})},html=templateTags(ctx),$el.find("div.tags-container").html(html)},showSaveButton=function(){return $el.find(".save").removeClass("hidden")},hideSaveButton=function(){return $el.find(".save").addClass("hidden")},resetInput=function(){return $el.find("input").val(""),$el.find("input").autocomplete("close")},addValue=function(value){var tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue,!1),null==tags&&(tags=[]),__indexOf.call(tags,value)<0&&tags.push(value),$scope.$apply(function(){return $model.$setViewValue(tags)})):void 0},deleteValue=function(value){var tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue,!1),tags=_.pull(tags,value),$scope.$apply(function(){return $model.$setViewValue(tags)})):void 0},saveInputTag=function(){var value;return value=$el.find("input").val(),addValue(value),resetInput(),hideSaveButton()},removeInputLastCharacter=function(){return function(input){var inputValue;return inputValue=input.val(),input.val(inputValue.substring(0,inputValue.length-1))}}(this),$el.on("keypress","input",function(event){return event.keyCode===ENTER_KEY?event.preventDefault():void 0}),$el.on("keyup","input",function(event){var target;return target=angular.element(event.currentTarget),event.keyCode===ENTER_KEY?saveInputTag():event.keyCode===COMMA_KEY?(removeInputLastCharacter(target),saveInputTag()):target.val().length?showSaveButton():hideSaveButton()}),$el.on("click",".save",function(event){return event.preventDefault(),saveInputTag()}),$el.on("click",".icon-delete",function(event){var target,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.siblings(".tag-name").text(),deleteValue(value)}),bindOnce($scope,"project",function(project){var positioningFunction;return positioningFunction=function(position,elements){var menu;return menu=elements.element.element,menu.css("width",elements.target.width),menu.css("top",position.top),menu.css("left",position.left)},$el.find("input").autocomplete({source:_.keys(project.tags_colors),position:{my:"left top",using:positioningFunction},select:function(event,ui){return addValue(ui.item.value),ui.item.value=""}})}),$scope.$watch($attrs.ngModel,function(tags){var tagsColors,_ref;return tagsColors=(null!=(_ref=$scope.project)?_ref.tags_colors:void 0)||[],renderTags(tags,tagsColors)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel",template:template}},module.directive("tgLbTagLine",["$tgResources",LbTagLineDirective]),TagLineDirective=function($rootScope,$repo,$rs,$confirm,$qqueue){var COMMA_KEY,ENTER_KEY,ESC_KEY,link,template,templateTags;return ENTER_KEY=13,ESC_KEY=27,COMMA_KEY=188,template='
    \n\n\n',templateTags=_.template('<% _.each(tags, function(tag) { %>\n \n <%- tag.name %>\n <% if (isEditable) { %>\n \n <% } %>\n \n<% }); %>'),link=function($scope,$el,$attrs,$model){var addValue,deleteValue,hideAddTagButton,hideAddTagButtonText,hideInput,hideSaveButton,isEditable,removeInputLastCharacter,renderInReadModeOnly,renderTags,resetInput,saveInputTag,showAddTagButton,showAddTagButtonText,showInput,showSaveButton;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},renderTags=function(tags,tagsColors){var ctx,html;return ctx={tags:_.map(tags,function(t){return{name:t,color:tagsColors[t]}}),isEditable:isEditable()},html=templateTags(ctx),$el.find("div.tags-container").html(html)},renderInReadModeOnly=function(){return $el.find(".add-tag").remove(),$el.find("input").remove(),$el.find(".save").remove()},showAddTagButton=function(){return $el.find(".add-tag").removeClass("hidden")},hideAddTagButton=function(){return $el.find(".add-tag").addClass("hidden")},showAddTagButtonText=function(){return $el.find(".add-tag-text").removeClass("hidden")},hideAddTagButtonText=function(){return $el.find(".add-tag-text").addClass("hidden")},showSaveButton=function(){return $el.find(".save").removeClass("hidden")},hideSaveButton=function(){return $el.find(".save").addClass("hidden")},showInput=function(){return $el.find("input").removeClass("hidden").focus()},hideInput=function(){return $el.find("input").addClass("hidden").blur()},resetInput=function(){return $el.find("input").val(""),$el.find("input").autocomplete("close")},addValue=$qqueue.bindAdd(function(value){var model,onError,onSuccess,tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue.tags,!1),null==tags&&(tags=[]),__indexOf.call(tags,value)<0&&tags.push(value),model=$model.$modelValue.clone(),model.tags=tags,$model.$setViewValue(model),onSuccess=function(){return $rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),model.revert(),$model.$setViewValue(model)},$repo.save(model).then(onSuccess,onError)):void 0}),deleteValue=$qqueue.bindAdd(function(value){var model,onError,onSuccess,tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue.tags,!1),tags=_.pull(tags,value),model=$model.$modelValue.clone(),model.tags=tags,$model.$setViewValue(model),onSuccess=function(){return $rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),model.revert(),$model.$setViewValue(model)},$repo.save(model).then(onSuccess,onError)):void 0}),saveInputTag=function(){var value;return value=$el.find("input").val(),addValue(value),resetInput(),hideSaveButton()},removeInputLastCharacter=function(){return function(input){var inputValue;return inputValue=input.val(),input.val(inputValue.substring(0,inputValue.length-1))}}(this),$el.on("keypress","input",function(event){var _ref;if((_ref=event.keyCode)===ENTER_KEY||_ref===ESC_KEY)return event.preventDefault()}),$el.on("keyup","input",function(event){var target;return target=angular.element(event.currentTarget),event.keyCode===ENTER_KEY?saveInputTag():event.keyCode===COMMA_KEY?(removeInputLastCharacter(target),saveInputTag()):event.keyCode===ESC_KEY?(resetInput(),hideInput(),hideSaveButton(),showAddTagButton()):target.val().length?showSaveButton():hideSaveButton()}),$el.on("click",".save",function(event){return event.preventDefault(),saveInputTag()}),$el.on("click",".add-tag",function(event){return event.preventDefault(),hideAddTagButton(),showInput()}),$el.on("click",".icon-delete",function(event){var target,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.siblings(".tag-name").text(),deleteValue(value)}),bindOnce($scope,"project",function(project){var positioningFunction;return isEditable()?(showAddTagButton(),positioningFunction=function(position,elements){var menu;return menu=elements.element.element,menu.css("width",elements.target.width),menu.css("top",position.top),menu.css("left",position.left)},$el.find("input").autocomplete({source:_.keys(project.tags_colors),position:{my:"left top",using:positioningFunction},select:function(event,ui){return addValue(ui.item.value),ui.item.value=""}})):void renderInReadModeOnly()}),$scope.$watch($attrs.ngModel,function(model){var tagsColors,_ref,_ref1;if(model)return(null!=(_ref=model.tags)?_ref.length:void 0)?hideAddTagButtonText():showAddTagButtonText(),tagsColors=(null!=(_ref1=$scope.project)?_ref1.tags_colors:void 0)||[],renderTags(model.tags,tagsColors)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel",template:template}},module.directive("tgTagLine",["$rootScope","$tgRepo","$tgResources","$tgConfirm","$tgQqueue",TagLineDirective])}.call(this),function(){var bindOnce,module,taiga,tgMarkitupDirective;taiga=this.taiga,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),tgMarkitupDirective=function($rootscope,$rs,$tr,$selectedText){var link,previewTemplate;return previewTemplate=_.template('
    \n
    \n \n
    \n
    \n <%= data %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var closePreviewMode,element,markdownCaretPositon,markdownSettings,markdownTitle,preview,previewDomNode,removeEmptyLine,setCaretPosition;return element=angular.element($el),previewDomNode=$("
    ",{"class":"preview"}),closePreviewMode=function(){return element.parents(".markdown").find(".preview").remove(),element.parents(".markItUp").show()},$scope.$on("markdown-editor:submit",function(){return closePreviewMode()}),preview=function(){var markItUpDomNode,markdownDomNode;return markdownDomNode=element.parents(".markdown"),markItUpDomNode=element.parents(".markItUp"),$rs.mdrender.render($scope.projectId,$model.$modelValue).then(function(data){var markdown;return markdownDomNode.append(previewTemplate({data:data.data})),markItUpDomNode.hide(),markdown=element.closest(".markdown"),markdown.on("mouseup.preview",".preview",function(event){var target;return event.preventDefault(),target=angular.element(event.target),target.is("a")||!$selectedText.get().length?(markdown.off(".preview"),closePreviewMode()):void 0})})},markdownCaretPositon=!1,setCaretPosition=function(elm,caretPos){var range;return elm.createTextRange?(range=elm.createTextRange(),range.move("character",caretPos),range.select()):elm.selectionStart?(elm.focus(),elm.setSelectionRange(caretPos,caretPos)):void 0},removeEmptyLine=function(textarea,line,currentCaretPosition){var lines,removedLineLength;return lines=textarea.value.split("\n"),removedLineLength=lines[line].length,lines[line]="",textarea.value=lines.join("\n"),currentCaretPosition-removedLineLength+1},markdownSettings={nameSpace:"markdown",onShiftEnter:{keepDefault:!1,openWith:"\n\n"},onEnter:{keepDefault:!1,replaceWith:function(){return function(data){var breakLineAtBeginning,cursorLine,emptyListItem,lastLine,lines,match,newLineContent;if(lines=data.textarea.value.split("\n"),cursorLine=data.textarea.value.slice(0,+(data.caretPosition-1)+1||9e9).split("\n").length,newLineContent=data.textarea.value.slice(data.caretPosition).split("\n")[0],lastLine=lines[cursorLine-1],match=lastLine.match(/^(\s*- ).*/))if(emptyListItem=lastLine.match(/^(\s*)\-\s$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)\-\s/),!breakLineAtBeginning&&match)return"\n"+match[1];if(match=lastLine.match(/^(\s*\* ).*/))if(emptyListItem=lastLine.match(/^(\s*\* )$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)\*\s/),!breakLineAtBeginning&&match)return"\n"+match[1];if(match=lastLine.match(/^(\s*)(\d+)\.\s/))if(emptyListItem=lastLine.match(/^(\s*)(\d+)\.\s$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)(\d+)\.\s/),!breakLineAtBeginning)return"\n"+(match[1]+(parseInt(match[2],10)+1))+". ";return"\n"}}(this),afterInsert:function(data){var caretPosition,line,scrollRelation,totalLines;return markdownCaretPositon?(setCaretPosition(data.textarea,markdownCaretPositon),caretPosition=markdownCaretPositon,markdownCaretPositon=!1):caretPosition=data.caretPosition,totalLines=data.textarea.value.split("\n").length,line=data.textarea.value.slice(0,+(caretPosition-1)+1||9e9).split("\n").length,scrollRelation=line/totalLines,$el.scrollTop(scrollRelation*$el[0].scrollHeight-$el.height()/2)}},markupSet:[{name:$tr.t("markdown-editor.heading-1"),key:"1",placeHolder:$tr.t("markdown-editor.placeholder"),closeWith:function(markItUp){return markdownTitle(markItUp,"=")}},{name:$tr.t("markdown-editor.heading-2"),key:"2",placeHolder:$tr.t("markdown-editor.placeholder"),closeWith:function(markItUp){return markdownTitle(markItUp,"-")}},{name:$tr.t("markdown-editor.heading-3"),key:"3",openWith:"### ",placeHolder:$tr.t("markdown-editor.placeholder")},{separator:"---------------"},{name:$tr.t("markdown-editor.bold"),key:"B",openWith:"**",closeWith:"**"},{name:$tr.t("markdown-editor.italic"),key:"I",openWith:"_",closeWith:"_"},{name:$tr.t("markdown-editor.strike"),key:"S",openWith:"~~",closeWith:"~~"},{separator:"---------------"},{name:$tr.t("markdown-editor.bulleted-list"),openWith:"- "},{name:$tr.t("markdown-editor.numeric-list"),openWith:function(markItUp){return markItUp.line+". "}},{separator:"---------------"},{name:$tr.t("markdown-editor.picture"),key:"P",replaceWith:'![[![Alternative text]!]]([![Url:!:http://]!] "[![Title]!]")'},{name:$tr.t("markdown-editor.link"),key:"L",openWith:"[",closeWith:']([![Url:!:http://]!] "[![Title]!]")',placeHolder:$tr.t("markdown-editor.link-placeholder")},{separator:"---------------"},{name:$tr.t("markdown-editor.quotes"),openWith:"> "},{name:$tr.t("markdown-editor.code-block"),openWith:"```\n",closeWith:"\n```"},{separator:"---------------"},{name:$tr.t("markdown-editor.preview"),call:preview,className:"preview-icon"}],afterInsert:function(event){var target;return target=angular.element(event.textarea),$model.$setViewValue(target.val())}},markdownTitle=function(markItUp,char){var heading,i,n,_i,_ref;for(heading="",n=$.trim(markItUp.selection||markItUp.placeHolder).length,i=_i=0,_ref=n-1;_ref>=0?_ref>=_i:_i>=_ref;i=_ref>=0?++_i:--_i)heading+=char;return"\n"+heading+"\n"},element.markItUp(markdownSettings),element.on("keypress",function(){return $scope.$apply()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgMarkitup",["$rootScope","$tgResources","$tgI18n","$selectedText",tgMarkitupDirective])}.call(this),function(){var BacklogFiltersDirective,bindOnce,debounceLeading,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,debounceLeading=this.taiga.debounceLeading,module=angular.module("taigaBacklog"),BacklogFiltersDirective=function(){var link,template,templateSelected;return template=_.template('<% _.each(filters, function(f) { %>\n <% if (f.selected) { %>\n \n style="border-left: 3px solid <%- f.color %>;"<% } %>>\n <%- f.name %>\n \n <%- f.count %>\n \n <% } else { %>\n \n style="border-left: 3px solid <%- f.color %>;"<% } %>>\n <%- f.name %>\n \n <%- f.count %>\n \n <% } %>\n<% }) %>'),templateSelected=_.template('<% _.each(filters, function(f) { %>\n\n style="border-left: 3px solid <%- f.color %>;"<% } %>>\n <%- f.name %>\n \n\n<% }) %>'),link=function($scope,$el){var $ctrl,initializeSelectedFilters,renderFilters,renderSelectedFilters,selectQFilter,selectedFilters,showCategories,showFilters,toggleFilterSelection; -return $ctrl=$el.closest(".wrapper").controller(),selectedFilters=[],showFilters=function(title,type){return $el.find(".filters-cats").hide(),$el.find(".filter-list").removeClass("hidden"),$el.find("h2.breadcrumb").removeClass("hidden"),$el.find("h2 a.subfilter span.title").html(title),$el.find("h2 a.subfilter span.title").prop("data-type",type)},showCategories=function(){return $el.find(".filters-cats").show(),$el.find(".filter-list").addClass("hidden"),$el.find("h2.breadcrumb").addClass("hidden")},initializeSelectedFilters=function(filters){var name,val,values,_i,_len;showCategories(),selectedFilters=[];for(name in filters)for(values=filters[name],_i=0,_len=values.length;_len>_i;_i++)val=values[_i],val.selected&&selectedFilters.push(val);return renderSelectedFilters()},renderSelectedFilters=function(){var html;return html=templateSelected({filters:selectedFilters}),$el.find(".filters-applied").html(html)},renderFilters=function(filters){var html;return html=template({filters:filters}),$el.find(".filter-list").html(html)},toggleFilterSelection=function(type,id){var currentFiltersType,filter,filters;return filters=$scope.filters[type],filter=_.find(filters,{id:taiga.toString(id)}),filter.selected=!filter.selected,filter.selected?(selectedFilters.push(filter),$scope.$apply(function(){return $ctrl.selectFilter(type,id),$ctrl.filterVisibleUserstories()})):(selectedFilters=_.reject(selectedFilters,filter),$scope.$apply(function(){return $ctrl.unselectFilter(type,id),$ctrl.filterVisibleUserstories()})),renderSelectedFilters(selectedFilters),currentFiltersType=$el.find("h2 a.subfilter span.title").prop("data-type"),type===currentFiltersType&&renderFilters(_.reject(filters,"selected")),$ctrl.loadUserstories()},selectQFilter=debounceLeading(100,function(value){return void 0!==value?(0===value.length?$ctrl.replaceFilter("q",null):$ctrl.replaceFilter("q",value),$ctrl.loadUserstories()):void 0}),$scope.$watch("filtersQ",selectQFilter),$scope.$on("filters:loaded",function(ctx,filters){return initializeSelectedFilters(filters)}),$el.on("click",".filters-cats > ul > li > a",function(event){var tags,target;return event.preventDefault(),target=angular.element(event.currentTarget),tags=$scope.filters[target.data("type")],renderFilters(_.reject(tags,"selected")),showFilters(target.attr("title"),target.data("type"))}),$el.on("click",".filters-inner > .filters-step-cat > .breadcrumb > .back",function(event){return event.preventDefault(),showCategories()}),$el.on("click",".filters-applied a",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),id=target.data("id"),type=target.data("type"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),target.hasClass("active")?target.removeClass("active"):target.addClass("active"),id=target.data("id"),type=target.data("type"),toggleFilterSelection(type,id)})},{link:link}},module.directive("tgBacklogFilters",["$log","$tgLocation",BacklogFiltersDirective])}.call(this),function(){var CreateEditSprint,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaBacklog"),CreateEditSprint=function($repo,$confirm,$rs,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var createSprint,hasErrors,remove,submit,submitButton;return hasErrors=!1,createSprint=!0,$scope.sprint={project:null,name:null,estimated_start:null,estimated_finish:null},submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,newSprint,promise,target;return event.preventDefault(),target=angular.element(event.currentTarget),form=$el.find("form").checksley(),form.validate()?(hasErrors=!1,newSprint=angular.copy($scope.sprint),broadcastEvent=null,createSprint?(newSprint.estimated_start=moment(newSprint.estimated_start).format("YYYY-MM-DD"),newSprint.estimated_finish=moment(newSprint.estimated_finish).format("YYYY-MM-DD"),promise=$repo.create("milestones",newSprint),broadcastEvent="sprintform:create:success"):(newSprint.setAttr("estimated_start",moment(newSprint.estimated_start).format("YYYY-MM-DD")),newSprint.setAttr("estimated_finish",moment(newSprint.estimated_finish).format("YYYY-MM-DD")),promise=$repo.save(newSprint),broadcastEvent="sprintform:edit:success"),$loading.start(submitButton),promise.then(function(data){return $loading.finish(submitButton),createSprint&&($scope.sprintsCounter+=1),$rootscope.$broadcast(broadcastEvent,data),lightboxService.close($el)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("light-error",data._error_message):data.__all__?$confirm.notify("light-error",data.__all__[0]):void 0})):(hasErrors=!0,void $el.find(".last-sprint-name").addClass("disappear"))}}(this)),remove=function(){var message,title;return title="Delete sprint",message=$scope.sprint.name,$confirm.askOnDelete(title,message).then(function(){return function(finish){var onError,onSuccess;return onSuccess=function(){return finish(),$scope.milestonesCounter-=1,lightboxService.close($el),$rootscope.$broadcast("sprintform:remove:success")},onError=function(){return finish(!1),$confirm.notify("error")},$repo.remove($scope.sprint).then(onSuccess,onError)}}(this))},$scope.$on("sprintform:create",function(event,projectId){var estimatedFinish,estimatedStart,lastSprint,lastSprintNameDom;return createSprint=!0,$scope.sprint.project=projectId,$scope.sprint.name=null,$scope.sprint.slug=null,lastSprint=$scope.sprints[0],estimatedStart=moment(),$scope.sprint.estimated_start?estimatedStart=moment($scope.sprint.estimated_start):null!=lastSprint&&(estimatedStart=moment(lastSprint.estimated_finish)),$scope.sprint.estimated_start=estimatedStart.format("DD MMM YYYY"),estimatedFinish=moment().add(2,"weeks"),$scope.sprint.estimated_finish?estimatedFinish=moment($scope.sprint.estimated_finish):null!=lastSprint&&(estimatedFinish=moment(lastSprint.estimated_finish).add(2,"weeks")),$scope.sprint.estimated_finish=estimatedFinish.format("DD MMM YYYY"),lastSprintNameDom=$el.find(".last-sprint-name"),null!=(null!=lastSprint?lastSprint.name:void 0)&&lastSprintNameDom.html(" last sprint is "+lastSprint.name+" ;-) "),$el.find(".delete-sprint").addClass("hidden"),$el.find(".title").text("New sprint"),$el.find(".button-green").text("Create"),lightboxService.open($el),$el.find(".sprint-name").focus()}),$scope.$on("sprintform:edit",function(ctx,sprint){return createSprint=!1,$scope.$apply(function(){return $scope.sprint=sprint,$scope.sprint.estimated_start=moment($scope.sprint.estimated_start).format("DD MMM YYYY"),$scope.sprint.estimated_finish=moment($scope.sprint.estimated_finish).format("DD MMM YYYY")}),$el.find(".delete-sprint").removeClass("hidden"),$el.find(".title").text("Edit sprint"),$el.find(".button-green").text("Save"),lightboxService.open($el),$el.find(".sprint-name").focus().select(),$el.find(".last-sprint-name").addClass("disappear")}),$el.on("keyup",".sprint-name",function(){return $el.find(".sprint-name").val().length>0||hasErrors?$el.find(".last-sprint-name").addClass("disappear"):$el.find(".last-sprint-name").removeClass("disappear")}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".delete-sprint .icon-delete",function(event){return event.preventDefault(),remove()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateEditSprint",["$tgRepo","$tgConfirm","$tgResources","$rootScope","lightboxService","$tgLoading",CreateEditSprint])}.call(this),function(){var BacklogController,BacklogDirective,TgBacklogProgressBarDirective,UsPointsDirective,UsRolePointsSelectorDirective,bindMethods,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,tgBacklogGraphDirective,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaBacklog"),BacklogController=function(_super){function BacklogController(scope,rootscope,repo,confirm,rs,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Backlog",this.showTags=!1,this.activeFilters=!1,this.excludeClosedSprints=!0,this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Backlog - "+_this.scope.project.name),_this.rs.userstories.getShowTags(_this.scope.projectId)?(_this.showTags=!0,_this.scope.$broadcast("showTags",_this.showTags)):void 0}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(BacklogController,_super),BacklogController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],BacklogController.prototype.initializeEventHandlers=function(){return this.scope.$on("usform:bulk:success",function(_this){return function(){return _this.loadUserstories(),_this.loadProjectStats(),_this.analytics.trackEvent("userstory","create","bulk create userstory on backlog",1)}}(this)),this.scope.$on("sprintform:create:success",function(_this){return function(){return _this.loadSprints(),_this.loadProjectStats(),_this.analytics.trackEvent("sprint","create","create sprint on backlog",1)}}(this)),this.scope.$on("usform:new:success",function(_this){return function(){return _this.loadUserstories(),_this.loadProjectStats(),_this.analytics.trackEvent("userstory","create","create userstory on backlog",1)}}(this)),this.scope.$on("sprintform:edit:success",function(_this){return function(){return _this.loadProjectStats()}}(this)),this.scope.$on("sprintform:remove:success",function(_this){return function(){return _this.loadSprints(),_this.loadProjectStats(),_this.loadUserstories()}}(this)),this.scope.$on("usform:edit:success",function(_this){return function(){return _this.loadUserstories()}}(this)),this.scope.$on("sprint:us:move",this.moveUs),this.scope.$on("sprint:us:moved",this.loadSprints),this.scope.$on("sprint:us:moved",this.loadProjectStats),this.scope.$on("backlog:toggle-closed-sprints-visualization",this.toggleClosedSprintsVisualization)},BacklogController.prototype.initializeSubscription=function(){var routingKey1,routingKey2;return routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.loadUserstories(),_this.loadSprints()}}(this)),routingKey2="changes.project."+this.scope.projectId+".milestones",this.events.subscribe(this.scope,routingKey2,function(_this){return function(){return _this.loadSprints()}}(this))},BacklogController.prototype.toggleShowTags=function(){return this.scope.$apply(function(_this){return function(){return _this.showTags=!_this.showTags,_this.rs.userstories.storeShowTags(_this.scope.projectId,_this.showTags)}}(this))},BacklogController.prototype.toggleActiveFilters=function(){return this.activeFilters=!this.activeFilters},BacklogController.prototype.loadProjectStats=function(){return this.rs.projects.stats(this.scope.projectId).then(function(_this){return function(stats){return _this.scope.stats=stats,_this.scope.stats.completedPercentage=stats.total_points?Math.round(100*stats.closed_points/stats.total_points):0,stats}}(this))},BacklogController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},BacklogController.prototype.loadSprints=function(){var params;return params={},this.excludeClosedSprints&&(params.closed=!1),this.rs.sprints.list(this.scope.projectId,params).then(function(_this){return function(sprints){var sprint,_i,_len;for(_i=0,_len=sprints.length;_len>_i;_i++)sprint=sprints[_i],sprint.user_stories=_.sortBy(sprint.user_stories,"sprint_order");return _this.scope.sprints=sprints,_this.scope.openSprints=_.filter(sprints,function(sprint){return!sprint.closed}).reverse(),_this.scope.closedSprints=_.filter(sprints,function(sprint){return sprint.closed}),_this.excludeClosedSprints||(_this.scope.totalClosedMilestones=_this.scope.closedSprints.length),_this.scope.sprintsCounter=sprints.length,_this.scope.sprintsById=groupBy(sprints,function(x){return x.id}),_this.rootscope.$broadcast("sprints:loaded",sprints),sprints}}(this))},BacklogController.prototype.resetFilters=function(){var selectedStatuses,selectedTags;return selectedTags=_.filter(this.scope.filters.tags,"selected"),selectedStatuses=_.filter(this.scope.filters.statuses,"selected"),this.scope.filtersQ="",_.each([selectedTags,selectedStatuses],function(_this){return function(filterGrp){return _.each(filterGrp,function(item){var filter,filters;return filters=_this.scope.filters[item.type],filter=_.find(filters,{id:taiga.toString(item.id)}),filter.selected=!1,_this.unselectFilter(item.type,item.id)})}}(this)),this.loadUserstories()},BacklogController.prototype.loadUserstories=function(){var promise;return this.scope.httpParams=this.getUrlFilters(),this.rs.userstories.storeQueryParams(this.scope.projectId,this.scope.httpParams),promise=this.q.all([this.refreshTagsColors(),this.rs.userstories.listUnassigned(this.scope.projectId,this.scope.httpParams)]),promise.then(function(_this){return function(data){var userstories;return userstories=data[1],_this.scope.userstories=_.sortBy(userstories,"backlog_order"),_this.generateFilters(),_this.filterVisibleUserstories(),_this.rootscope.$broadcast("filters:loaded",_this.scope.filters),scopeDefer(_this.scope,function(){return _this.scope.$broadcast("userstories:loaded")}),userstories}}(this))},BacklogController.prototype.loadBacklog=function(){return this.q.all([this.loadProjectStats(),this.loadSprints(),this.loadUserstories()])},BacklogController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.totalClosedMilestones=project.total_closed_milestones,_this.scope.$emit("project:loaded",project),_this.scope.points=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(x){return x.id}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.usStatusList=_.sortBy(project.us_statuses,"id"),project}}(this))},BacklogController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription()}}(this)),promise.then(function(_this){return function(){return _this.loadBacklog()}}(this))},BacklogController.prototype.toggleClosedSprintsVisualization=function(){return this.excludeClosedSprints=!this.excludeClosedSprints,this.loadSprints()},BacklogController.prototype.filterVisibleUserstories=function(){var selectedStatuses,selectedTags;return this.scope.visibleUserstories=[],selectedTags=_.filter(this.scope.filters.tags,"selected"),selectedTags=_.map(selectedTags,"name"),this.scope.visibleUserstories=0===selectedTags.length?_.clone(this.scope.userstories,!1):_.reject(this.scope.userstories,function(){return function(us){return 0===_.intersection(selectedTags,us.tags).length?!0:!1}}(this)),selectedStatuses=_.filter(this.scope.filters.statuses,"selected"),selectedStatuses=_.map(selectedStatuses,"id"),selectedStatuses.length>0&&(this.scope.visibleUserstories=_.reject(this.scope.visibleUserstories,function(){return function(us){var res;return res=_.find(selectedStatuses,function(x){return x===taiga.toString(us.status)}),!res}}(this))),this.rs.userstories.storeQueryParams(this.scope.projectId,{status:selectedStatuses,tags:selectedTags,project:this.scope.projectId,milestone:null})},BacklogController.prototype.prepareBulkUpdateData=function(uses,field){return null==field&&(field="backlog_order"),_.map(uses,function(x){return{us_id:x.id,order:x[field]}})},BacklogController.prototype.resortUserStories=function(uses,field){var index,item,items,_i,_len;for(null==field&&(field="backlog_order"),items=[],index=_i=0,_len=uses.length;_len>_i;index=++_i)item=uses[index],item[field]=index,item.isModified()&&items.push(item);return items},BacklogController.prototype.moveUs=function(ctx,usList,newUsIndex,newSprintId){var data,items,newSprint,oldSprintId,project,promise,promises,us,userstories,_i,_j,_k,_len,_len1,_len2;if(oldSprintId=usList[0].milestone,project=usList[0].project,newSprintId===oldSprintId)return items=null,userstories=null,userstories=null===newSprintId?this.scope.userstories:this.scope.sprintsById[newSprintId].user_stories,this.scope.$apply(function(){var args,key,r,us,_i,_len;for(key=_i=0,_len=usList.length;_len>_i;key=++_i)us=usList[key],r=userstories.indexOf(us),userstories.splice(r,1);return args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(userstories,args)}),null===newSprintId?(items=this.resortUserStories(userstories,"backlog_order"),data=this.prepareBulkUpdateData(items,"backlog_order"),this.rs.userstories.bulkUpdateBacklogOrder(project,data).then(function(_this){return function(){var us,_i,_len,_results;for(_results=[],_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results}}(this))):(items=this.resortUserStories(userstories,"sprint_order"),data=this.prepareBulkUpdateData(items,"sprint_order"),this.rs.userstories.bulkUpdateSprintOrder(project,data).then(function(_this){return function(){var us,_i,_len,_results;for(_results=[],_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results}}(this))),promise;if(null===newSprintId){for(_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],us.milestone=null;return this.scope.$apply(function(_this){return function(){var args,key,r,sprint,_j,_len1,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(_this.scope.userstories,args),Array.prototype.splice.apply(_this.scope.visibleUserstories,args),_this.filterVisibleUserstories(),sprint=_this.scope.sprintsById[oldSprintId],_results=[],key=_j=0,_len1=usList.length;_len1>_j;key=++_j)us=usList[key],r=sprint.user_stories.indexOf(us),_results.push(sprint.user_stories.splice(r,1));return _results}}(this)),promise=this.repo.save(us),promise=promise.then(function(_this){return function(){return items=_this.resortUserStories(_this.scope.userstories,"backlog_order"),data=_this.prepareBulkUpdateData(items,"backlog_order"),_this.rs.userstories.bulkUpdateBacklogOrder(us.project,data).then(function(){return _this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId)})}}(this)),promise.then(null,function(){return console.log("FAIL")}),promise}if(newSprint=this.scope.sprintsById[newSprintId],null===oldSprintId){for(_j=0,_len1=usList.length;_len1>_j;_j++)us=usList[_j],us.milestone=newSprintId;this.scope.$apply(function(_this){return function(){var args,key,r,_k,_len2,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(newSprint.user_stories,args),_results=[],key=_k=0,_len2=usList.length;_len2>_k;key=++_k)us=usList[key],r=_this.scope.visibleUserstories.indexOf(us),_this.scope.visibleUserstories.splice(r,1),r=_this.scope.userstories.indexOf(us),_results.push(_this.scope.userstories.splice(r,1));return _results}}(this))}else{for(_k=0,_len2=usList.length;_len2>_k;_k++)us=usList[_k],us.milestone=newSprintId;this.scope.$apply(function(_this){return function(){var args,oldSprint,r,_l,_len3,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(newSprint.user_stories,args),_results=[],_l=0,_len3=usList.length;_len3>_l;_l++)us=usList[_l],oldSprint=_this.scope.sprintsById[oldSprintId],r=oldSprint.user_stories.indexOf(us),_results.push(oldSprint.user_stories.splice(r,1));return _results}}(this))}return promises=_.map(usList,function(_this){return function(us){return _this.repo.save(us)}}(this)),promise=this.q.all(promises).then(function(_this){return function(){return items=_this.resortUserStories(newSprint.user_stories,"sprint_order"),data=_this.prepareBulkUpdateData(items,"sprint_order"),_this.rs.userstories.bulkUpdateSprintOrder(project,data).then(function(){return _this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId)}),_this.rs.userstories.bulkUpdateBacklogOrder(project,data).then(function(){var _l,_len3,_results;for(_results=[],_l=0,_len3=usList.length;_len3>_l;_l++)us=usList[_l],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results})}}(this)),promise.then(null,function(){return console.log("FAIL")}),promise},BacklogController.prototype.getUrlFilters=function(){return _.pick(this.location.search(),"statuses","tags","q")},BacklogController.prototype.generateFilters=function(){var isSelected,name,plainStatuses,plainTags,searchdata,urlfilters,val,value,_i,_len,_ref;urlfilters=this.getUrlFilters(),urlfilters.q&&(this.scope.filtersQ=urlfilters.q),searchdata={};for(name in urlfilters)for(value=urlfilters[name],null==searchdata[name]&&(searchdata[name]={}),_ref=taiga.toString(value).split(","),_i=0,_len=_ref.length;_len>_i;_i++)val=_ref[_i],searchdata[name][val]=!0;return isSelected=function(type,id){return null!=searchdata[type]&&searchdata[type][id]?!0:!1},this.scope.filters={},plainTags=_.flatten(_.filter(_.map(this.scope.userstories,"tags"))),plainTags.sort(),this.scope.filters.tags=_.map(_.countBy(plainTags),function(_this){return function(v,k){var obj;return obj={id:k,type:"tags",name:k,color:_this.scope.project.tags_colors[k],count:v},isSelected("tags",obj.id)&&(obj.selected=!0),obj}}(this)),plainStatuses=_.map(this.scope.userstories,"status"),plainStatuses=_.filter(plainStatuses,function(){return function(status){return status?status:void 0}}(this)),this.scope.filters.statuses=_.map(_.countBy(plainStatuses),function(_this){return function(v,k){var obj;return obj={id:k,type:"statuses",name:_this.scope.usStatusById[k].name,color:_this.scope.usStatusById[k].color,count:v},isSelected("statuses",obj.id)&&(obj.selected=!0),obj}}(this)),this.scope.filters},BacklogController.prototype.editUserStory=function(us){return this.rootscope.$broadcast("usform:edit",us)},BacklogController.prototype.deleteUserStory=function(us){var message,title;return title="Delete User Story",message=us.subject,this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var promise;return _this.scope.userstories=_.without(_this.scope.userstories,us),_this.filterVisibleUserstories(),promise=_this.repo.remove(us),promise.then(function(){return finish(),_this.loadBacklog()}),promise.then(null,function(){return finish(!1),_this.confirm.notify("error")})}}(this))},BacklogController.prototype.addNewUs=function(type){switch(type){case"standard":return this.rootscope.$broadcast("usform:new",this.scope.projectId,this.scope.project.default_us_status,this.scope.usStatusList);case"bulk":return this.rootscope.$broadcast("usform:bulk",this.scope.projectId,this.scope.project.default_us_status)}},BacklogController.prototype.addNewSprint=function(){return this.rootscope.$broadcast("sprintform:create",this.scope.projectId)},BacklogController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("BacklogController",BacklogController),BacklogDirective=function($repo,$rootscope){var doomLineTemplate,link,linkDoomLine,linkFilters,linkToolbar,showHideFilter,showHideTags;return doomLineTemplate=_.template('
    Project Scope [Doomline]
    '),linkDoomLine=function($scope,$el){var addDoomLineDom,getUsItems,reloadDoomLine,removeDoomlineDom;return reloadDoomLine=function(){var current_sum,element,elements,scope,stats,total_points,_i,_len,_results;if(null!=$scope.stats){for(removeDoomlineDom(),elements=getUsItems(),stats=$scope.stats,total_points=stats.total_points,current_sum=stats.assigned_points,_results=[],_i=0,_len=elements.length;_len>_i;_i++)if(element=elements[_i],scope=element.scope(),null!=scope.us){if(current_sum+=scope.us.total_points,current_sum>total_points){addDoomLineDom(element);break}_results.push(void 0)}return _results}},removeDoomlineDom=function(){return $el.find(".doom-line").remove()},addDoomLineDom=function(element){return null!=element?element.before(doomLineTemplate({})):void 0},getUsItems=function(){var rowElements;return rowElements=$el.find(".backlog-table-body .us-item-row"),_.map(rowElements,function(x){return angular.element(x)})},$scope.$on("userstories:loaded",reloadDoomLine),$scope.$watch("stats",reloadDoomLine)},linkToolbar=function($scope,$el,$attrs,$ctrl){var moveToCurrentSprint;return moveToCurrentSprint=function(selectedUss){var extraPoints,totalExtraPoints,ussCurrent;return ussCurrent=_($scope.userstories),$scope.userstories=ussCurrent.without.apply(ussCurrent,selectedUss).value(),extraPoints=_.map(selectedUss,function(v){return v.total_points}),totalExtraPoints=_.reduce(extraPoints,function(acc,num){return acc+num}),$scope.sprints[0].user_stories=_.union($scope.sprints[0].user_stories,selectedUss),$scope.sprints[0].total_points+=totalExtraPoints,$ctrl.filterVisibleUserstories(),$repo.saveAll(selectedUss).then(function(){return $ctrl.loadSprints(),$ctrl.loadProjectStats()})},$el.on("change",".backlog-table-body .user-stories input:checkbox",function(event){var moveToCurrentSprintDom,selectedUsDom,target;return target=angular.element(event.currentTarget),moveToCurrentSprintDom=$el.find("#move-to-current-sprint"),selectedUsDom=$el.find(".backlog-table-body .user-stories input:checkbox:checked"),selectedUsDom.length>0&&$scope.sprints.length>0?moveToCurrentSprintDom.show():moveToCurrentSprintDom.hide(),target.closest(".us-item-row").toggleClass("ui-multisortable-multiple")}),$el.on("click","#move-to-current-sprint",function(){return function(){var ussDom,ussToMove;return ussDom=$el.find(".backlog-table-body .user-stories input:checkbox:checked"),ussToMove=_.map(ussDom,function(item){var itemScope;return itemScope=angular.element(item).scope(),itemScope.us.milestone=$scope.sprints[0].id,itemScope.us}),$scope.$apply(_.partial(moveToCurrentSprint,ussToMove))}}(this)),$el.on("click","#show-tags",function(event){return event.preventDefault(),$ctrl.toggleShowTags(),showHideTags($ctrl)})},showHideTags=function($ctrl){var elm;return elm=angular.element("#show-tags"),$ctrl.showTags?(elm.addClass("active"),elm.find(".text").text("Hide Tags")):(elm.removeClass("active"),elm.find(".text").text("Show Tags"))},showHideFilter=function($scope,$el,$ctrl){var sidebar,target;return sidebar=$el.find("sidebar.filters-bar"),sidebar.one("transitionend",function(){return timeout(150,function(){return $rootscope.$broadcast("resize"),$(".burndown").css("visibility","visible")})}),target=angular.element("#show-filters-button"),$(".burndown").css("visibility","hidden"),sidebar.toggleClass("active"),target.toggleClass("active"),toggleText(target.find(".text"),["Remove Filters","Show Filters"]),sidebar.hasClass("active")||$ctrl.resetFilters(),$ctrl.toggleActiveFilters()},linkFilters=function($scope,$el,$attrs,$ctrl){return $scope.filtersSearch={},$el.on("click","#show-filters-button",function(event){return event.preventDefault(),$scope.$apply(function(){return showHideFilter($scope,$el,$ctrl)})})},link=function($scope,$el,$attrs){var $ctrl,filters;return $ctrl=$el.controller(),linkToolbar($scope,$el,$attrs,$ctrl),linkFilters($scope,$el,$attrs,$ctrl),linkDoomLine($scope,$el,$attrs,$ctrl),$el.find(".backlog-table-body").disableSelection(),filters=$ctrl.getUrlFilters(),(filters.statuses||filters.tags||filters.q)&&showHideFilter($scope,$el,$ctrl),$scope.$on("showTags",function(){return showHideTags($ctrl)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklog",["$tgRepo","$rootScope",BacklogDirective]),UsRolePointsSelectorDirective=function($rootscope){var link,selectionTemplate;return selectionTemplate=_.template(''),link=function($scope,$el){return bindOnce($scope,"project",function(project){var numberOfRoles,roles;return roles=_.filter(project.roles,"computable"),numberOfRoles=_.size(roles),numberOfRoles>1?$el.append(selectionTemplate({roles:roles})):($el.find(".icon-arrow-bottom").remove(),$el.find(".header-points").addClass("not-clickable"))}),$scope.$on("uspoints:select",function(ctx,roleId,roleName){return $el.find(".popover").popover().close(),$el.find(".header-points").html(""+roleName+"/Total")}),$scope.$on("uspoints:clear-selection",function(){return $el.find(".popover").popover().close(),$el.find(".header-points").text("Points")}),$el.on("click",function(event){var target;return target=angular.element(event.target),(target.is("span")||target.is("div"))&&event.stopPropagation(),$el.find(".popover").popover().open()}),$el.on("click",".clear-selection",function(event){return event.preventDefault(),event.stopPropagation(),$rootscope.$broadcast("uspoints:clear-selection")}),$el.on("click",".role",function(event){var rolScope,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),rolScope=target.scope(),$rootscope.$broadcast("uspoints:select",target.data("role-id"),target.text())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUsRolePointsSelector",["$rootScope",UsRolePointsSelectorDirective]),UsPointsDirective=function($repo){var link,pointsTemplate,rolesTemplate;return rolesTemplate=_.template(''),pointsTemplate=_.template(''),link=function($scope,$el,$attrs){var $ctrl,calculateTotalPoints,computableRoles,numberOfRoles,renderPoints,renderPointsSelector,renderRolesSelector,roles,selectedRoleId,updatePointsRoles,updatingSelectedRoleId,us;return $ctrl=$el.controller(),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=null,selectedRoleId=null,numberOfRoles=_.size(us.points),1===numberOfRoles&&(selectedRoleId=_.keys(us.points)[0]),roles=[],updatePointsRoles=function(){return roles=_.map(computableRoles,function(role){var pointId,pointObj; -return pointId=us.points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj.value?pointObj.value:"?",role})},computableRoles=_.filter($scope.project.roles,"computable"),updatePointsRoles(),0===roles.length&&($el.find(".icon-arrow-bottom").remove(),$el.find("a.us-points").addClass("not-clickable")),renderPointsSelector=function(us,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=us.points[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),$el.append(html),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").popover().open()},renderRolesSelector=function(){var html;return updatePointsRoles(),html=rolesTemplate({roles:roles}),$el.append(html),$el.find(".pop-role").popover().open(function(){return $(this).remove()})},renderPoints=function(us,roleId){var dom,pointId,pointObj,totalPoints;return dom=$el.find("a > span.points-value"),null===roleId||1===numberOfRoles?(totalPoints=null!=us.total_points?us.total_points:"?",dom.text(totalPoints),dom.parent().prop("title",totalPoints)):(pointId=us.points[roleId],pointObj=$scope.pointsById[pointId],dom.html(""+pointObj.name+" / "+us.total_points+""),dom.parent().prop("title",""+pointObj.name+" / "+us.total_points))},calculateTotalPoints=function(){var values;return values=_.map(us.points,function(v){return $scope.pointsById[v].value}),values=_.filter(values,function(num){return null!=num}),0===values.length?"?":_.reduce(values,function(acc,num){return acc+num})},$scope.$watch($attrs.tgBacklogUsPoints,function(us){return us?renderPoints(us,selectedRoleId):void 0}),$scope.$on("uspoints:select",function(ctx,roleId){return us=$scope.$eval($attrs.tgBacklogUsPoints),renderPoints(us,roleId),selectedRoleId=roleId}),$scope.$on("uspoints:clear-selection",function(){return us=$scope.$eval($attrs.tgBacklogUsPoints),renderPoints(us,null),selectedRoleId=null}),roles.length>0&&($el.on("click","a.us-points span",function(event){return event.preventDefault(),event.stopPropagation(),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=selectedRoleId,null!=selectedRoleId?renderPointsSelector(us,selectedRoleId):renderRolesSelector(us)}),$el.on("click",".role",function(event){var popRolesDom,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=target.data("role-id"),popRolesDom=$el.find(".pop-role"),popRolesDom.find("a").removeClass("active"),popRolesDom.find("a[data-role-id='"+updatingSelectedRoleId+"']").addClass("active"),renderPointsSelector(us,updatingSelectedRoleId)}),$el.on("click",".point",function(event){var points,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),$el.find(".pop-points-open").hide(),$el.find(".pop-role").hide(),us=$scope.$eval($attrs.tgBacklogUsPoints),points=_.clone(us.points,!0),points[updatingSelectedRoleId]=target.data("point-id"),$scope.$apply(function(){return us.points=points,us.total_points=calculateTotalPoints(us),renderPoints(us,selectedRoleId),$repo.save(us).then(function(){return $repo.refresh(us).then(function(){return $ctrl.loadProjectStats()})})})})),bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_us")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogUsPoints",["$tgRepo",UsPointsDirective]),tgBacklogGraphDirective=function(){var link,redrawChart;return redrawChart=function(element,dataToDraw){var client_increment_line,colors,data,evolution_line,milestonesRange,optimal_line,options,team_increment_line,width,zero_line,_results;return width=element.width(),element.height(width/6),milestonesRange=function(){_results=[];for(var _i=0,_ref=dataToDraw.milestones.length-1;_ref>=0?_ref>=_i:_i>=_ref;_ref>=0?_i++:_i--)_results.push(_i);return _results}.apply(this),data=[],zero_line=_.map(dataToDraw.milestones,function(){return 0}),data.push({data:_.zip(milestonesRange,zero_line),lines:{fillColor:"rgba(0,0,0,0)"},points:{show:!1}}),optimal_line=_.map(dataToDraw.milestones,function(ml){return ml.optimal}),data.push({data:_.zip(milestonesRange,optimal_line),lines:{fillColor:"rgba(120,120,120,0.2)"}}),evolution_line=_.filter(_.map(dataToDraw.milestones,function(ml){return ml.evolution}),function(evolution){return null!=evolution}),data.push({data:_.zip(milestonesRange,evolution_line),lines:{fillColor:"rgba(102,153,51,0.3)"}}),team_increment_line=_.map(dataToDraw.milestones,function(ml){return-ml["team-increment"]}),data.push({data:_.zip(milestonesRange,team_increment_line),lines:{fillColor:"rgba(153,51,51,0.3)"}}),client_increment_line=_.map(dataToDraw.milestones,function(ml){return-ml["team-increment"]-ml["client-increment"]}),data.push({data:_.zip(milestonesRange,client_increment_line),lines:{fillColor:"rgba(255,51,51,0.3)"}}),colors=["rgba(0,0,0,1)","rgba(120,120,120,0.2)","rgba(102,153,51,1)","rgba(153,51,51,1)","rgba(255,51,51,1)"],options={grid:{borderWidth:{top:0,right:1,left:0,bottom:0},borderColor:"#ccc",hoverable:!0},xaxis:{ticks:dataToDraw.milestones.length,axisLabel:"Sprints",axisLabelUseCanvas:!0,axisLabelFontSizePixels:14,axisLabelFontFamily:"Verdana, Arial, Helvetica, Tahoma, sans-serif",axisLabelPadding:15,tickFormatter:function(){return""}},series:{shadowSize:0,lines:{show:!0,fill:!0},points:{show:!0,fill:!0,radius:4,lineWidth:2}},colors:colors,tooltip:!0,tooltipOpts:{content:function(label,xval,yval,flotItem){return 1===flotItem.seriesIndex?"Optimal pending points for sprint "+xval+" should be "+yval:2===flotItem.seriesIndex?"Real pending points for sprint "+xval+" is "+yval:3===flotItem.seriesIndex?"Incremented points by team requirements for sprint "+xval+" is "+Math.abs(yval):"Incremented points by client requirements for sprint "+xval+" is "+Math.abs(yval)}}},element.empty(),element.plot(data,options).data("plot")},link=function($scope,$el){var element;return element=angular.element($el),$scope.$watch("stats",function(){return null!=$scope.stats?(redrawChart(element,$scope.stats),$scope.$on("resize",function(){return redrawChart(element,$scope.stats)})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgGmBacklogGraph",tgBacklogGraphDirective),TgBacklogProgressBarDirective=function(){var adjustPercentaje,link,render,template;return template=_.template('
    \n
    \n
    '),render=function(el,projectPointsPercentaje,closedPointsPercentaje){return el.html(template({projectPointsPercentaje:projectPointsPercentaje,closedPointsPercentaje:closedPointsPercentaje}))},adjustPercentaje=function(percentage){var adjusted;return adjusted=_.max([0,percentage]),adjusted=_.min([100,adjusted]),Math.round(adjusted)},link=function($scope,$el,$attrs){var element;return element=angular.element($el),$scope.$watch($attrs.tgBacklogProgressBar,function(stats){var closedPoints,closedPointsPercentaje,definedPoints,projectPointsPercentaje,totalPoints;return null!=stats?(totalPoints=stats.total_points,definedPoints=stats.defined_points,closedPoints=stats.closed_points,definedPoints>totalPoints?(projectPointsPercentaje=100*totalPoints/definedPoints,closedPointsPercentaje=100*closedPoints/definedPoints):(projectPointsPercentaje=100,closedPointsPercentaje=100*closedPoints/totalPoints),projectPointsPercentaje=adjustPercentaje(projectPointsPercentaje-3),closedPointsPercentaje=adjustPercentaje(closedPointsPercentaje-3),render($el,projectPointsPercentaje,closedPointsPercentaje)):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogProgressBar",TgBacklogProgressBarDirective)}.call(this),function(){var BacklogEmptySortableDirective,BacklogSortableDirective,SprintSortableDirective,bindOnce,deleteElement,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,module=angular.module("taigaBacklog"),deleteElement=function(el){return el.scope().$destroy(),el.off(),el.remove()},BacklogSortableDirective=function($repo,$rs,$rootscope,$tgConfirm){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){var filterError;if(project.my_permissions.indexOf("modify_us")>-1)return filterError=function(){return $tgConfirm.notify("error","You can't drop on backlog when filters are open")},$el.sortable({connectWith:".sprint",containment:".wrapper",dropOnEmpty:!0,placeholder:"row us-item-row us-item-drag sortable-placeholder",scroll:!0,tolerance:"pointer",revert:!1,cursorAt:{right:15},stop:function(){return $el.hasClass("active-filters")?($el.sortable("cancel"),filterError()):void 0}}),$el.on("multiplesortreceive",function(event,ui){var itemIndex,itemUs;return $el.hasClass("active-filters")?(ui.source.sortable("cancel"),void filterError()):(itemUs=ui.item.scope().us,itemIndex=ui.item.index(),deleteElement(ui.item),$scope.$emit("sprint:us:move",[itemUs],itemIndex,null),ui.item.find("a").removeClass("noclick"))}),$el.on("multiplesortstop",function(event,ui){var index,items,us;if(0!==$(ui.items[0]).parent().length)return items=_.sortBy(ui.items,function(item){return $(item).index()}),index=_.min(_.map(items,function(item){return $(item).index()})),us=_.map(items,function(item){var itemUs;return item=$(item),itemUs=item.scope().us,setTimeout(function(){return function(){return item.find("a").removeClass("noclick")}}(this),300),itemUs}),$scope.$emit("sprint:us:move",us,index,null)}),$el.on("sortstart",function(event,ui){return ui.item.find("a").addClass("noclick")})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},BacklogEmptySortableDirective=function(){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?($el.sortable({dropOnEmpty:!0}),$el.on("sortreceive",function(event,ui){var itemIndex,itemUs;return itemUs=ui.item.scope().us,itemIndex=ui.item.index(),deleteElement(ui.item),$scope.$emit("sprint:us:move",[itemUs],itemIndex,null),ui.item.find("a").removeClass("noclick")})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},SprintSortableDirective=function(){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?($el.sortable({scroll:!0,dropOnEmpty:!0,items:".sprint-table .milestone-us-item-row",connectWith:".sprint,.backlog-table-body,.empty-backlog"}),$el.on("multiplesortreceive",function(event,ui){var index,items,us;return items=_.sortBy(ui.items,function(item){return $(item).index()}),index=_.min(_.map(items,function(item){return $(item).index()})),us=_.map(items,function(item){var itemUs;return item=$(item),itemUs=item.scope().us,deleteElement(item),itemUs}),$scope.$emit("sprint:us:move",us,index,$scope.sprint.id)}),$el.on("multiplesortstop",function(event,ui){var itemIndex,itemUs;if(0!==ui.item.parent().length)return itemUs=ui.item.scope().us,itemIndex=ui.item.index(),setTimeout(function(){return function(){return ui.item.find("a").removeClass("noclick")}}(this),300),$scope.$emit("sprint:us:move",[itemUs],itemIndex,$scope.sprint.id)}),$el.on("sortstart",function(event,ui){return ui.item.find("a").addClass("noclick")})):void 0})},{link:link}},module.directive("tgBacklogSortable",["$tgRepo","$tgResources","$rootScope","$tgConfirm",BacklogSortableDirective]),module.directive("tgBacklogEmptySortable",["$tgRepo","$tgResources","$rootScope",BacklogEmptySortableDirective]),module.directive("tgSprintSortable",["$tgRepo","$tgResources","$rootScope",SprintSortableDirective])}.call(this),function(){var BacklogSprintDirective,BacklogSprintHeaderDirective,ToggleExcludeClosedSprintsVisualization,module,taiga;taiga=this.taiga,module=angular.module("taigaBacklog"),BacklogSprintDirective=function($repo,$rootscope){var link,refreshSprintTableHeight,slideOptions,sprintTableMinHeight,toggleSprint;return sprintTableMinHeight=50,slideOptions={duration:500,easing:"linear"},refreshSprintTableHeight=function(){return function(sprintTable){return sprintTable.find(".row").length?sprintTable.css("height","auto"):sprintTable.css("height",sprintTableMinHeight)}}(this),toggleSprint=function(){return function($el){var sprintArrow,sprintTable;return sprintTable=$el.find(".sprint-table"),sprintArrow=$el.find(".icon-arrow-up"),sprintArrow.toggleClass("active"),sprintTable.toggleClass("open"),refreshSprintTableHeight(sprintTable)}}(this),link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgBacklogSprint,function(sprint){return sprint=$scope.$eval($attrs.tgBacklogSprint),$scope.$first?toggleSprint($el):sprint.closed?$el.addClass("sprint-closed"):$scope.$first||sprint.closed?void 0:(toggleSprint($el),$el.addClass("sprint-old-open"))}),$el.on("click",".sprint-name > .icon-arrow-up",function(){return toggleSprint($el),$el.find(".sprint-table").slideToggle(slideOptions)}),$el.on("click",".sprint-name > .icon-edit",function(){var sprint;return sprint=$scope.$eval($attrs.tgBacklogSprint),$rootscope.$broadcast("sprintform:edit",sprint)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogSprint",["$tgRepo","$rootScope",BacklogSprintDirective]),BacklogSprintHeaderDirective=function($navUrls){var link,template;return template=_.template('
    \n \n\n <% if(isVisible){ %>\n \n <%- name %>\n \n <% } %>\n\n <% if(isEditable){ %>\n \n <% } %>\n
    \n\n
    \n
    <%- estimatedDateRange %>
    \n
      \n
    • \n <%- closedPoints %>\n closed\n
    • \n
    • \n <%- totalPoints %>\n total\n
    • \n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,isVisible,render;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_milestone")},isVisible=function(){return-1!==$scope.project.my_permissions.indexOf("view_milestones")},render=function(sprint){var ctx,estimatedDateRange,finish,start,taskboardUrl;return taskboardUrl=$navUrls.resolve("project-taskboard",{project:$scope.project.slug,sprint:sprint.slug}),start=moment(sprint.estimated_start).format("DD MMM YYYY"),finish=moment(sprint.estimated_finish).format("DD MMM YYYY"),estimatedDateRange=""+start+"-"+finish,ctx={name:sprint.name,taskboardUrl:taskboardUrl,estimatedDateRange:estimatedDateRange,closedPoints:sprint.closed_points||0,totalPoints:sprint.total_points||0,isVisible:isVisible(),isEditable:isEditable()},$el.html(template(ctx))},$scope.$watch($attrs.ngModel,function(sprint){return render(sprint)}),$scope.$on("sprintform:edit:success",function(){return render($model.$modelValue)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgBacklogSprintHeader",["$tgNavUrls","$tgRepo","$rootScope",BacklogSprintHeaderDirective]),ToggleExcludeClosedSprintsVisualization=function($rootscope,$loading){var excludeClosedSprints,link;return excludeClosedSprints=!1,link=function($scope,$el){return $el.on("click","",function(){return $loading.start($el.siblings(".load")),$rootscope.$broadcast("backlog:toggle-closed-sprints-visualization")}),$scope.$on("$destroy",function(){return $el.off()}),$scope.$on("sprints:loaded",function(){return function(ctx,sprints){var closedSprints;return closedSprints=_.filter(sprints,function(sprint){return sprint.closed}),$loading.finish($el.siblings(".load")),$el.text(closedSprints.length>0?"Hide closed sprints":"Show closed sprints")}}(this))},{link:link}},module.directive("tgBacklogToggleClosedSprintsVisualization",["$rootScope","$tgLoading",ToggleExcludeClosedSprintsVisualization])}.call(this),function(){var SprintGraphDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,module=angular.module("taigaTaskboard"),SprintGraphDirective=function(){var link,redrawChart;return redrawChart=function(element,dataToDraw){var data,days,options,width;return width=element.width(),element.height(240),days=_.map(dataToDraw,function(x){return moment(x.day)}),data=[],data.unshift({data:_.zip(days,_.map(dataToDraw,function(d){return d.optimal_points})),lines:{fillColor:"rgba(120,120,120,0.2)"}}),data.unshift({data:_.zip(days,_.map(dataToDraw,function(d){return d.open_points})),lines:{fillColor:"rgba(102,153,51,0.3)"}}),options={grid:{borderWidth:{top:0,right:1,left:0,bottom:0},borderColor:"#ccc",hoverable:!0},xaxis:{tickSize:[1,"day"],min:days[0],max:_.last(days),mode:"time",daysNames:days,axisLabel:"Day",axisLabelUseCanvas:!0,axisLabelFontSizePixels:12,axisLabelFontFamily:"Verdana, Arial, Helvetica, Tahoma, sans-serif",axisLabelPadding:5},yaxis:{min:0},series:{shadowSize:0,lines:{show:!0,fill:!0},points:{show:!0,fill:!0,radius:4,lineWidth:2}},colors:["rgba(102,153,51,1)","rgba(120,120,120,0.2)"],tooltip:!0,tooltipOpts:{content:function(label,xval,yval,flotItem){var formattedDate,roundedValue;return formattedDate=moment(xval).format("DD MMM"),roundedValue=Math.round(yval),1===flotItem.seriesIndex?"Optimal pending points for day "+formattedDate+" should be "+roundedValue:"Real pending points for day "+formattedDate+" is "+roundedValue}}},element.empty(),element.plot(data,options).data("plot")},link=function($scope,$el){var element;return element=angular.element($el),$scope.$on("resize",function(){return $scope.stats?redrawChart(element,$scope.stats.days):void 0}),$scope.$on("taskboard:graph:toggle-visibility",function(){return $el.parent().toggleClass("open"),timeout(100,function(){return $scope.stats?redrawChart(element,$scope.stats.days):void 0})}),$scope.$watch("stats",function(){return null!=$scope.stats?redrawChart(element,$scope.stats.days):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgSprintGraph",SprintGraphDirective)}.call(this),function(){var CreateBulkTasksDirective,CreateEditTaskDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,CreateEditTaskDirective=function($repo,$model,$rs,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.isNew=!0,$scope.$on("taskform:new",function(ctx,sprintId,usId){return $scope.task={project:$scope.projectId,milestone:sprintId,user_story:usId,is_archived:!1,status:$scope.project.default_task_status,assigned_to:null,tags:[]},$scope.isNew=!0,$el.find(".button-green span").html("Create"),$el.find(".title").html("New task "),$el.find(".tag-input").val(""),lightboxService.open($el)}),$scope.$on("taskform:edit",function(ctx,task){return $scope.task=task,$scope.isNew=!1,$el.find(".button-green span").html("Save"),$el.find(".title").html("Edit task "),$el.find(".tag-input").val(""),lightboxService.open($el)}),submitButton=$el.find(".submit-button"),submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($scope.isNew?(promise=$repo.create("tasks",$scope.task),broadcastEvent="taskform:new:success"):(promise=$repo.save($scope.task),broadcastEvent="taskform:edit:success"),$loading.start(submitButton),promise.then(function(data){return $loading.finish(submitButton),lightboxService.close($el),$rootscope.$broadcast(broadcastEvent,data)})):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},CreateBulkTasksDirective=function($repo,$rs,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.form={data:"",usId:null},submit=debounce(2e3,function(){return function(event){var data,form,projectId,promise,sprintId,usId;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),data=$scope.form.data,projectId=$scope.projectId,sprintId=$scope.form.sprintId,usId=$scope.form.usId,promise=$rs.tasks.bulkCreate(projectId,sprintId,usId,data),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("taskform:bulk:success",result),lightboxService.close($el)}),promise.then(null,function(){return $loading.finish(submitButton),console.log("FAIL")})):void 0}}(this)),$scope.$on("taskform:bulk",function(ctx,sprintId,usId){return lightboxService.open($el),$scope.form={data:"",sprintId:sprintId,usId:usId}}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaTaskboard"),module.directive("tgLbCreateEditTask",["$tgRepo","$tgModel","$tgResources","$rootScope","$tgLoading","lightboxService",CreateEditTaskDirective]),module.directive("tgLbCreateBulkTasks",["$tgRepo","$tgResources","$rootScope","$tgLoading","lightboxService",CreateBulkTasksDirective])}.call(this),function(){var TaskboardController,TaskboardDirective,TaskboardSquishColumnDirective,TaskboardTableHeightFixerDirective,TaskboardTaskDirective,TaskboardUserDirective,bindMethods,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,toggleText=this.taiga.toggleText,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,scopeDefer=this.taiga.scopeDefer,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaTaskboard"),TaskboardController=function(_super){function TaskboardController(scope,rootscope,repo,confirm,rs,params,q,appTitle,location,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.appTitle=appTitle,this.location=location,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Taskboard",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Taskboard - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TaskboardController,_super),TaskboardController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$appTitle","$tgLocation","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],TaskboardController.prototype.initializeEventHandlers=function(){return this.scope.$on("taskform:bulk:success",function(_this){return function(){return _this.loadTaskboard(),_this.analytics.trackEvent("task","create","bulk create task on taskboard",1)}}(this)),this.scope.$on("taskform:new:success",function(_this){return function(){return _this.loadTaskboard(),_this.analytics.trackEvent("task","create","create task on taskboard",1)}}(this)),this.scope.$on("taskform:edit:success",function(_this){return function(){return _this.loadTaskboard()}}(this)),this.scope.$on("taskboard:task:move",this.taskMove),this.scope.$on("assigned-to:added",function(_this){return function(ctx,userId,task){var promise;return task.assigned_to=userId,promise=_this.repo.save(task),promise.then(null,function(){return console.log("FAIL")})}}(this))},TaskboardController.prototype.initializeSubscription=function(){var routingKey,routingKey1;return routingKey="changes.project."+this.scope.projectId+".tasks",this.events.subscribe(this.scope,routingKey,function(_this){return function(){return _this.loadTaskboard()}}(this)),routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.refreshTagsColors(),_this.loadSprintStats(),_this.loadSprint()}}(this))},TaskboardController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(e){return e.id}),_this.scope.roleById=groupBy(project.roles,function(e){return e.id}),_this.scope.taskStatusList=_.sortBy(project.task_statuses,"order"),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.scope.usStatusById=groupBy(project.us_statuses,function(e){return e.id}),_this.scope.$emit("project:loaded",project),project}}(this))},TaskboardController.prototype.loadSprintStats=function(){return this.rs.sprints.stats(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(stats){var completedPointsSum,remainingPointsSum,remainingTasks,totalPointsSum;return totalPointsSum=_.reduce(_.values(stats.total_points),function(res,n){return res+n},0),completedPointsSum=_.reduce(_.values(stats.completed_points),function(res,n){return res+n},0),remainingPointsSum=totalPointsSum-completedPointsSum,remainingTasks=stats.total_tasks-stats.completed_tasks,_this.scope.stats=stats,_this.scope.stats.totalPointsSum=totalPointsSum,_this.scope.stats.completedPointsSum=completedPointsSum,_this.scope.stats.remainingPointsSum=remainingPointsSum,_this.scope.stats.remainingTasks=remainingTasks,_this.scope.stats.completedPercentage=stats.totalPointsSum?Math.round(100*stats.completedPointsSum/stats.totalPointsSum):0,_this.scope.stats.openTasks=stats.total_tasks-stats.completed_tasks,stats}}(this))},TaskboardController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},TaskboardController.prototype.loadSprint=function(){return this.rs.sprints.get(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,_this.scope.userstories=_.sortBy(sprint.user_stories,"sprint_order"),sprint}}(this))},TaskboardController.prototype.loadTasks=function(){return this.rs.tasks.list(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(tasks){var status,task,us,_i,_j,_k,_len,_len1,_len2,_ref,_ref1,_ref2;for(_this.scope.tasks=_.sortBy(tasks,"taskboard_order"),_this.scope.usTasks={},_ref=_.union(_this.scope.userstories,[{id:null}]),_i=0,_len=_ref.length;_len>_i;_i++)for(us=_ref[_i],_this.scope.usTasks[us.id]={},_ref1=_this.scope.taskStatusList,_j=0,_len1=_ref1.length;_len1>_j;_j++)status=_ref1[_j],_this.scope.usTasks[us.id][status.id]=[];for(_ref2=_this.scope.tasks,_k=0,_len2=_ref2.length;_len2>_k;_k++)task=_ref2[_k],null!=_this.scope.usTasks[task.user_story]&&null!=_this.scope.usTasks[task.user_story][task.status]&&_this.scope.usTasks[task.user_story][task.status].push(task);return tasks}}(this))},TaskboardController.prototype.loadTaskboard=function(){return this.q.all([this.refreshTagsColors(),this.loadSprintStats(),this.loadSprint().then(function(_this){return function(){return _this.loadTasks()}}(this))])},TaskboardController.prototype.loadInitialData=function(){var params,promise;return params={pslug:this.params.pslug,sslug:this.params.sslug},promise=this.repo.resolve(params).then(function(_this){return function(data){return _this.scope.projectId=data.project,_this.scope.sprintId=data.milestone,_this.initializeSubscription(),data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadTaskboard()}}(this))},TaskboardController.prototype.refreshTasksOrder=function(tasks){var data,items;return items=this.resortTasks(tasks),data=this.prepareBulkUpdateData(items),this.rs.tasks.bulkUpdateTaskTaskboardOrder(this.scope.project.id,data)},TaskboardController.prototype.resortTasks=function(tasks){var index,item,items,_i,_len;for(items=[],index=_i=0,_len=tasks.length;_len>_i;index=++_i)item=tasks[index],item.taskboard_order=index,item.isModified()&&items.push(item);return items},TaskboardController.prototype.prepareBulkUpdateData=function(uses){return _.map(uses,function(x){return{task_id:x.id,order:x.taskboard_order}})},TaskboardController.prototype.taskMove=function(ctx,task,usId,statusId,order){var promise,r,tasks;return r=this.scope.usTasks[task.user_story][task.status].indexOf(task),this.scope.usTasks[task.user_story][task.status].splice(r,1),tasks=this.scope.usTasks[usId][statusId],tasks.splice(order,0,task),task.user_story=usId,task.status=statusId,task.taskboard_order=order,promise=this.repo.save(task),this.rootscope.$broadcast("sprint:task:moved",task),promise.then(function(_this){return function(){return _this.refreshTasksOrder(tasks),_this.loadSprintStats()}}(this)),promise.then(null,function(){return function(){return console.log("FAIL TASK SAVE")}}(this))},TaskboardController.prototype.addNewTask=function(type,us){switch(type){case"standard":return this.rootscope.$broadcast("taskform:new",this.scope.sprintId,null!=us?us.id:void 0);case"bulk":return this.rootscope.$broadcast("taskform:bulk",this.scope.sprintId,null!=us?us.id:void 0)}},TaskboardController.prototype.editTaskAssignedTo=function(task){return this.rootscope.$broadcast("assigned-to:add",task)},TaskboardController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TaskboardController",TaskboardController),TaskboardDirective=function($rootscope){var link;return link=function($scope,$el){var $ctrl,tableBodyDom;return $ctrl=$el.controller(),$el.on("click",".toggle-analytics-visibility",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.toggleClass("active"),$rootscope.$broadcast("taskboard:graph:toggle-visibility")}),tableBodyDom=$el.find(".taskboard-table-body"),tableBodyDom.on("scroll",function(event){var tableHeaderDom,target;return target=angular.element(event.currentTarget),tableHeaderDom=$el.find(".taskboard-table-header .taskboard-table-inner"),tableHeaderDom.css("left",-1*target.scrollLeft())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgTaskboard",["$rootScope",TaskboardDirective]),TaskboardTaskDirective=function($rootscope){var link;return link=function($scope,$el){return $el.disableSelection(),$scope.$watch("task",function(task){return task.is_blocked&&!$el.hasClass("blocked")?$el.addClass("blocked"):!task.is_blocked&&$el.hasClass("blocked")?$el.removeClass("blocked"):void 0 -}),$el.find(".icon-edit").on("click",function(){return $el.find(".icon-edit").hasClass("noclick")?void 0:$scope.$apply(function(){return $rootscope.$broadcast("taskform:edit",$scope.task)})})},{link:link}},module.directive("tgTaskboardTask",["$rootScope",TaskboardTaskDirective]),TaskboardTableHeightFixerDirective=function(){var link,mainPadding,renderSize;return mainPadding=32,renderSize=function($el){var columnHeight,elementOffset,windowHeight;return elementOffset=$el.offset().top,windowHeight=angular.element(window).height(),columnHeight=windowHeight-elementOffset-mainPadding,$el.css("height",""+columnHeight+"px")},link=function($scope,$el){return timeout(500,function(){return renderSize($el)}),$scope.$on("resize",function(){return renderSize($el)})},{link:link}},module.directive("tgTaskboardTableHeightFixer",TaskboardTableHeightFixerDirective),TaskboardSquishColumnDirective=function(rs){var avatarWidth,link;return avatarWidth=40,link=function($scope,$el){var getCeilWidth,recalculateStatusColumnWidth,recalculateTaskboardWidth,refreshTaskboardTableWidth,setStatusColumnWidth;return $scope.$on("sprint:task:moved",function(){return function(){return recalculateTaskboardWidth()}}(this)),bindOnce($scope,"usTasks",function(){return $scope.statusesFolded=rs.tasks.getStatusColumnModes($scope.project.id),$scope.usFolded=rs.tasks.getUsRowModes($scope.project.id,$scope.sprintId),recalculateTaskboardWidth()}),$scope.foldStatus=function(status){return $scope.statusesFolded[status.id]=!$scope.statusesFolded[status.id],rs.tasks.storeStatusColumnModes($scope.projectId,$scope.statusesFolded),recalculateTaskboardWidth()},$scope.foldUs=function(us){return us?$scope.usFolded[us.id]=!$scope.usFolded[us.id]:$scope.usFolded[null]=!$scope.usFolded[null],rs.tasks.storeUsRowModes($scope.projectId,$scope.sprintId,$scope.usFolded),recalculateTaskboardWidth()},getCeilWidth=function(){return function(usId,statusId){var tasks,tasksMatrixSize,width;return tasks=$scope.usTasks[usId][statusId].length,$scope.statusesFolded[statusId]?(tasks&&$scope.usFolded[usId]?(tasksMatrixSize=Math.round(Math.sqrt(tasks)),width=avatarWidth*tasksMatrixSize):width=avatarWidth,width):0}}(this),setStatusColumnWidth=function(){return function(statusId,width){var column;return column=$el.find(".squish-status-"+statusId),width?column.css("max-width",width):column.css("max-width","none")}}(this),refreshTaskboardTableWidth=function(){return function(){var columnWidths,columns,totalWidth;return columnWidths=[],columns=$el.find(".task-colum-name"),columnWidths=_.map(columns,function(column){return $(column).outerWidth(!0)}),totalWidth=_.reduce(columnWidths,function(total,width){return total+width}),$el.find(".taskboard-table-inner").css("width",totalWidth)}}(this),recalculateStatusColumnWidth=function(){return function(statusId){var statusFoldedWidth;return statusFoldedWidth=getCeilWidth(null,statusId),_.forEach($scope.userstories,function(us){var width;return width=getCeilWidth(us.id,statusId),width>statusFoldedWidth?statusFoldedWidth=width:void 0}),setStatusColumnWidth(statusId,statusFoldedWidth)}}(this),recalculateTaskboardWidth=function(){return function(){_.forEach($scope.taskStatusList,function(status){return recalculateStatusColumnWidth(status.id)}),refreshTaskboardTableWidth()}}(this)},{link:link}},module.directive("tgTaskboardSquishColumn",["$tgResources",TaskboardSquishColumnDirective]),TaskboardUserDirective=function(){var clickable,link,template;return template='
    \n \n \n \n
    \n\n',clickable=!1,link=function($scope,$el){var username_label;return username_label=$el.parent().find("a.task-assigned"),username_label.on("click",function(){var $ctrl;if(!$el.find("a").hasClass("noclick"))return $ctrl=$el.controller(),$ctrl.editTaskAssignedTo($scope.task)}),$scope.$watch("task.assigned_to",function(assigned_to){var user;return user=$scope.usersById[assigned_to],void 0===user?_.assign($scope,{name:"Unassigned",imgurl:"/images/unnamed.png",clickable:clickable}):_.assign($scope,{name:user.full_name_display,imgurl:user.photo,clickable:clickable}),username_label.text($scope.name)}),bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_task")>-1?(clickable=!0,$el.find(".avatar-assigned-to").on("click",function(){return function(){var $ctrl;if(!$el.find("a").hasClass("noclick"))return $ctrl=$el.controller(),$ctrl.editTaskAssignedTo($scope.task)}}(this))):void 0})},{link:link,template:template,scope:{usersById:"=users",project:"=",task:"="}}},module.directive("tgTaskboardUserAvatar",["$log",TaskboardUserDirective])}.call(this),function(){var TaskboardSortableDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,module=angular.module("taigaBacklog"),TaskboardSortableDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){var deleteElement,itemEl,newParentScope,oldParentScope,tdom;return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el,deleteElement=function(itemEl){return itemEl.scope().$destroy(),itemEl.off(),itemEl.remove()},tdom.sortable({handle:".taskboard-task-inner",dropOnEmpty:!0,connectWith:".taskboard-tasks-box",revert:400}),tdom.on("sortstop",function(event,ui){var itemIndex,itemTask,newStatusId,newUsId,oldStatusId,oldUsId,parentEl;return parentEl=ui.item.parent(),itemEl=ui.item,itemTask=itemEl.scope().task,itemIndex=itemEl.index(),newParentScope=parentEl.scope(),oldUsId=oldParentScope.us?oldParentScope.us.id:null,oldStatusId=oldParentScope.st.id,newUsId=newParentScope.us?newParentScope.us.id:null,newStatusId=newParentScope.st.id,(newStatusId!==oldStatusId||newUsId!==oldUsId)&&deleteElement(itemEl),$scope.$apply(function(){return $rootscope.$broadcast("taskboard:task:move",itemTask,newUsId,newStatusId,itemIndex)}),ui.item.find("a").removeClass("noclick")}),tdom.on("sortstart",function(event,ui){return oldParentScope=ui.item.parent().scope(),ui.item.find("a").addClass("noclick")}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgTaskboardSortable",["$tgRepo","$tgResources","$rootScope",TaskboardSortableDirective])}.call(this),function(){var KanbanArchivedStatusHeaderDirective,KanbanArchivedStatusIntroDirective,KanbanColumnHeightFixerDirective,KanbanController,KanbanDirective,KanbanSquishColumnDirective,KanbanUserDirective,KanbanUserstoryDirective,KanbanWipLimitDirective,bindMethods,bindOnce,defaultViewMode,defaultViewModes,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaKanban"),defaultViewMode="maximized",defaultViewModes={maximized:{cardClass:"kanban-task-maximized"},minimized:{cardClass:"kanban-task-minimized"}},KanbanController=function(_super){function KanbanController(scope,rootscope,repo,confirm,rs,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Kanban",this.scope.statusViewModes={},this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Kanban - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(KanbanController,_super),KanbanController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],KanbanController.prototype.initializeEventHandlers=function(){return this.scope.$on("usform:new:success",function(_this){return function(){return _this.loadUserstories(),_this.refreshTagsColors(),_this.analytics.trackEvent("userstory","create","create userstory on kanban",1)}}(this)),this.scope.$on("usform:bulk:success",function(_this){return function(){return _this.loadUserstories(),_this.analytics.trackEvent("userstory","create","bulk create userstory on kanban",1)}}(this)),this.scope.$on("usform:edit:success",function(_this){return function(){return _this.loadUserstories(),_this.refreshTagsColors()}}(this)),this.scope.$on("assigned-to:added",this.onAssignedToChanged),this.scope.$on("kanban:us:move",this.moveUs),this.scope.$on("kanban:show-userstories-for-status",this.loadUserStoriesForStatus),this.scope.$on("kanban:hide-userstories-for-status",this.hideUserStoriesForStatus)},KanbanController.prototype.addNewUs=function(type,statusId){switch(type){case"standard":return this.rootscope.$broadcast("usform:new",this.scope.projectId,statusId,this.scope.usStatusList);case"bulk":return this.rootscope.$broadcast("usform:bulk",this.scope.projectId,statusId)}},KanbanController.prototype.changeUsAssignedTo=function(us){return this.rootscope.$broadcast("assigned-to:add",us)},KanbanController.prototype.onAssignedToChanged=function(ctx,userid,us){var promise;return us.assigned_to=userid,promise=this.repo.save(us),promise.then(null,function(){return console.log("FAIL")})},KanbanController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},KanbanController.prototype.loadUserstories=function(){var params;return params={status__is_archived:!1},this.rs.userstories.listAll(this.scope.projectId,params).then(function(_this){return function(userstories){var status,usByStatus,_i,_len,_ref;for(_this.scope.userstories=userstories,usByStatus=_.groupBy(userstories,"status"),_ref=_this.scope.usStatusList,_i=0,_len=_ref.length;_len>_i;_i++)status=_ref[_i],null==usByStatus[status.id]&&(usByStatus[status.id]=[]),status.is_archived&&null!=_this.scope.usByStatus&&(usByStatus[status.id]=_this.scope.usByStatus[status.id]),usByStatus[status.id]=_.sortBy(usByStatus[status.id],"kanban_order");return _this.scope.usByStatus=usByStatus,scopeDefer(_this.scope,function(){return _this.scope.$broadcast("userstories:loaded",userstories)}),userstories}}(this))},KanbanController.prototype.loadUserStoriesForStatus=function(ctx,statusId){var params;return params={status:statusId},this.rs.userstories.listAll(this.scope.projectId,params).then(function(_this){return function(userstories){return _this.scope.usByStatus[statusId]=_.sortBy(userstories,"kanban_order"),_this.scope.$broadcast("kanban:shown-userstories-for-status",statusId,userstories),userstories}}(this))},KanbanController.prototype.hideUserStoriesForStatus=function(ctx,statusId){return this.scope.usByStatus[statusId]=[],this.scope.$broadcast("kanban:hidden-userstories-for-status",statusId)},KanbanController.prototype.loadKanban=function(){return this.q.all([this.refreshTagsColors(),this.loadUserstories()])},KanbanController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.projectId=project.id,_this.scope.points=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(x){return x.id}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.generateStatusViewModes(),_this.scope.$emit("project:loaded",project),project}}(this))},KanbanController.prototype.initializeSubscription=function(){var routingKey1;return routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.loadUserstories()}}(this))},KanbanController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription(),_this.loadKanban().then(function(){return _this.scope.$broadcast("redraw:wip")})}}(this))},KanbanController.prototype.generateStatusViewModes=function(){var mode,status,storedStatusViewModes,_i,_len,_ref;for(storedStatusViewModes=this.rs.kanban.getStatusViewModes(this.scope.projectId),this.scope.statusViewModes={},_ref=this.scope.usStatusList,_i=0,_len=_ref.length;_len>_i;_i++)status=_ref[_i],mode=storedStatusViewModes[status.id],this.scope.statusViewModes[status.id]=_.has(defaultViewModes,mode)?mode:defaultViewMode;return this.storeStatusViewModes()},KanbanController.prototype.storeStatusViewModes=function(){return this.rs.kanban.storeStatusViewModes(this.scope.projectId,this.scope.statusViewModes)},KanbanController.prototype.updateStatusViewMode=function(statusId,newViewMode){return this.scope.statusViewModes[statusId]=newViewMode,this.storeStatusViewModes()},KanbanController.prototype.getCardClass=function(statusId){var mode;return mode=this.scope.statusViewModes[statusId]||defaultViewMode,defaultViewModes[mode].cardClass||defaultViewModes[defaultViewMode].cardClass},KanbanController.prototype.prepareBulkUpdateData=function(uses,field){return null==field&&(field="kanban_order"),_.map(uses,function(x){return{us_id:x.id,order:x[field]}})},KanbanController.prototype.resortUserStories=function(uses){var index,item,items,_i,_len;for(items=[],index=_i=0,_len=uses.length;_len>_i;index=++_i)item=uses[index],item.kanban_order=index,item.isModified()&&items.push(item);return items},KanbanController.prototype.moveUs=function(ctx,us,oldStatusId,newStatusId,index){var itemsToSave,promise,r;return oldStatusId!==newStatusId?(r=this.scope.usByStatus[oldStatusId].indexOf(us),this.scope.usByStatus[oldStatusId].splice(r,1),this.scope.usByStatus[newStatusId].splice(index,0,us),us.status=newStatusId):(r=this.scope.usByStatus[newStatusId].indexOf(us),this.scope.usByStatus[newStatusId].splice(r,1),this.scope.usByStatus[newStatusId].splice(index,0,us)),itemsToSave=this.resortUserStories(this.scope.usByStatus[newStatusId]),this.scope.usByStatus[newStatusId]=_.sortBy(this.scope.usByStatus[newStatusId],"kanban_order"),promise=this.repo.save(us),promise=promise.then(function(_this){return function(){var data;return itemsToSave=_.reject(itemsToSave,{id:us.id}),data=_this.prepareBulkUpdateData(itemsToSave),_this.rs.userstories.bulkUpdateKanbanOrder(us.project,data).then(function(){return itemsToSave})}}(this))},KanbanController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("KanbanController",KanbanController),KanbanDirective=function(){var link;return link=function($scope,$el){var tableBodyDom;return tableBodyDom=$el.find(".kanban-table-body"),tableBodyDom.on("scroll",function(event){var tableHeaderDom,target;return target=angular.element(event.currentTarget),tableHeaderDom=$el.find(".kanban-table-header .kanban-table-inner"),tableHeaderDom.css("left",-1*target.scrollLeft())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanban",["$tgRepo","$rootScope",KanbanDirective]),KanbanColumnHeightFixerDirective=function(){var link,mainPadding,renderSize,scrollPadding;return mainPadding=32,scrollPadding=0,renderSize=function($el){var columnHeight,elementOffset,windowHeight;return elementOffset=$el.parent().parent().offset().top,windowHeight=angular.element(window).height(),columnHeight=windowHeight-elementOffset-mainPadding-scrollPadding,$el.css("height",""+columnHeight+"px")},link=function($scope,$el){return timeout(500,function(){return renderSize($el)}),$scope.$on("resize",function(){return renderSize($el)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanColumnHeightFixer",KanbanColumnHeightFixerDirective),KanbanArchivedStatusHeaderDirective=function($rootscope){var hideArchivedText,link,showArchivedText;return showArchivedText="Show archived",hideArchivedText="Hide archived",link=function($scope,$el,$attrs){var hidden,status;return status=$scope.$eval($attrs.tgKanbanArchivedStatusHeader),hidden=!0,$scope["class"]="icon icon-open-eye",$scope.title=showArchivedText,$el.on("click",function(){return hidden=!hidden,$scope.$apply(function(){return hidden?($scope["class"]="icon icon-open-eye",$scope.title=showArchivedText,$rootscope.$broadcast("kanban:hide-userstories-for-status",status.id)):($scope["class"]="icon icon-closed-eye",$scope.title=hideArchivedText,$rootscope.$broadcast("kanban:show-userstories-for-status",status.id))})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanArchivedStatusHeader",["$rootScope",KanbanArchivedStatusHeaderDirective]),KanbanArchivedStatusIntroDirective=function(){var hiddenUserStoriexText,link,userStories;return hiddenUserStoriexText="The user stories in this status are hidden by default",userStories=[],link=function($scope,$el,$attrs){var status,updateIntroText;return status=$scope.$eval($attrs.tgKanbanArchivedStatusIntro),$el.text(hiddenUserStoriexText),updateIntroText=function(){return $el.text(userStories.length>0?"":hiddenUserStoriexText)},$scope.$on("kanban:us:move",function(ctx,itemUs,oldStatusId,newStatusId,itemIndex){var r;return status.id===newStatusId?status.id===oldStatusId?(r=userStories.indexOf(itemUs),userStories.splice(r,1),userStories.splice(itemIndex,0,itemUs)):(itemUs.isArchived=!0,userStories.splice(itemIndex,0,itemUs)):status.id===oldStatusId&&(itemUs.isArchived=!1,r=userStories.indexOf(itemUs),userStories.splice(r,1)),updateIntroText()}),$scope.$on("kanban:shown-userstories-for-status",function(ctx,statusId,userStoriesLoaded){return statusId===status.id?(userStories=_.filter(userStoriesLoaded,function(us){return us.status===status.id}),updateIntroText()):void 0}),$scope.$on("kanban:hidden-userstories-for-status",function(ctx,statusId){return statusId===status.id?(userStories=[],updateIntroText()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanArchivedStatusIntro",KanbanArchivedStatusIntroDirective),KanbanUserstoryDirective=function($rootscope){var link;return link=function($scope,$el,$attrs,$model){return $el.disableSelection(),$scope.$watch("us",function(us){return us.is_blocked&&!$el.hasClass("blocked")?$el.addClass("blocked"):!us.is_blocked&&$el.hasClass("blocked")?$el.removeClass("blocked"):void 0}),$el.find(".icon-edit").on("click",function(){return $el.find(".icon-edit").hasClass("noclick")?void 0:$scope.$apply(function(){return $rootscope.$broadcast("usform:edit",$model.$modelValue)})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"/partials/views/components/kanban-task.html",link:link,require:"ngModel"}},module.directive("tgKanbanUserstory",["$rootScope",KanbanUserstoryDirective]),KanbanSquishColumnDirective=function(rs){var link;return link=function($scope,$el){var updateTableWidth;return $scope.$on("project:loaded",function(event,project){return $scope.folds=rs.kanban.getStatusColumnModes(project.id),updateTableWidth()}),$scope.foldStatus=function(status){$scope.folds[status.id]=!$scope.folds[status.id],rs.kanban.storeStatusColumnModes($scope.projectId,$scope.folds),updateTableWidth()},updateTableWidth=function(){var columnWidths,totalWidth;return columnWidths=_.map($scope.usStatusList,function(status){return $scope.folds[status.id]?40:310}),totalWidth=_.reduce(columnWidths,function(total,width){return total+width}),$el.find(".kanban-table-inner").css("width",totalWidth)}},{link:link}},module.directive("tgKanbanSquishColumn",["$tgResources",KanbanSquishColumnDirective]),KanbanWipLimitDirective=function(){var link;return link=function($scope,$el,$attrs){var redrawWipLimit;return $el.disableSelection(),redrawWipLimit=function(){return $el.find(".kanban-wip-limit").remove(),timeout(200,function(){var element;return element=$el.find(".kanban-task")[$scope.$eval($attrs.tgKanbanWipLimit)],element?angular.element(element).before("
    "):void 0})},$scope.$on("redraw:wip",redrawWipLimit),$scope.$on("kanban:us:move",redrawWipLimit),$scope.$on("usform:new:success",redrawWipLimit),$scope.$on("usform:bulk:success",redrawWipLimit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanWipLimit",KanbanWipLimitDirective),KanbanUserDirective=function($log){var clickable,link,template;return template=_.template('
    \n class="not-clickable"<% } %>>\n <%- name %>\n \n
    '),clickable=!1,link=function($scope,$el,$attrs,$model){var render,wtid;return $attrs.tgKanbanUserAvatar?(wtid=$scope.$watch($attrs.tgKanbanUserAvatar,function(v){var user;return null==$scope.usersById?($log.error("KanbanUserDirective requires userById set in scope."),wtid()):(user=$scope.usersById[v],render(user))}),render=function(user){var ctx,html,username_label;return ctx=void 0===user?{name:"Unassigned",imgurl:"/images/unnamed.png",clickable:clickable}:{name:user.full_name_display,imgurl:user.photo,clickable:clickable},html=template(ctx),$el.html(html),username_label=$el.parent().find("a.task-assigned"),username_label.html(ctx.name),username_label.on("click",function(){var $ctrl,us;if(!$el.find("a").hasClass("noclick"))return us=$model.$modelValue,$ctrl=$el.controller(),$ctrl.changeUsAssignedTo(us)})},bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?(clickable=!0,$el.on("click",function(){return function(){var $ctrl,us;if(!$el.find("a").hasClass("noclick"))return us=$model.$modelValue,$ctrl=$el.controller(),$ctrl.changeUsAssignedTo(us)}}(this))):void 0}),$scope.$on("$destroy",function(){return $el.off()})):$log.error("KanbanUserDirective: no attr is defined")},{link:link,require:"ngModel"}},module.directive("tgKanbanUserAvatar",["$log",KanbanUserDirective])}.call(this),function(){var KanbanSortableDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,module=angular.module("taigaKanban"),KanbanSortableDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){var deleteElement,itemEl,newParentScope,oldParentScope,tdom;if(project.my_permissions.indexOf("modify_us")>-1)return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el,deleteElement=function(itemEl){return itemEl.scope().$destroy(),itemEl.off(),itemEl.remove()},tdom.sortable({handle:".kanban-task-inner",dropOnEmpty:!0,connectWith:".kanban-uses-box",revert:400}),tdom.on("sortstop",function(event,ui){var itemIndex,itemUs,newStatusId,oldStatusId,parentEl;return parentEl=ui.item.parent(),itemEl=ui.item,itemUs=itemEl.scope().us,itemIndex=itemEl.index(),newParentScope=parentEl.scope(),newStatusId=newParentScope.s.id,oldStatusId=oldParentScope.s.id,newStatusId!==oldStatusId&&deleteElement(itemEl),$scope.$apply(function(){return $rootscope.$broadcast("kanban:us:move",itemUs,itemUs.status,newStatusId,itemIndex)}),ui.item.find("a").removeClass("noclick")}),tdom.on("sortstart",function(event,ui){return oldParentScope=ui.item.parent().scope(),ui.item.find("a").addClass("noclick")})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanSortable",["$tgRepo","$tgResources","$rootScope",KanbanSortableDirective])}.call(this),function(){var IssueDetailController,IssuePriorityButtonDirective,IssueSeverityButtonDirective,IssueStatusButtonDirective,IssueStatusDisplayDirective,IssueTypeButtonDirective,PromoteIssueToUsButtonDirective,bindOnce,groupBy,joinStr,mixOf,module,taiga,toString,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaIssues"),IssueDetailController=function(_super){function IssueDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,analytics,navUrls,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.analytics=analytics,this.navUrls=navUrls,this.scope.issueRef=this.params.issueref,this.scope.sectionName="Issue Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.issue.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(IssueDetailController,_super),IssueDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgAnalytics","$tgNavUrls","tgLoader"],IssueDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("attachment:create",function(_this){return function(){return _this.rootscope.$broadcast("history:reload"),_this.analytics.trackEvent("attachment","create","create attachment on issue",1)}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("promote-issue-to-us:success",function(_this){return function(){return _this.analytics.trackEvent("issue","promoteToUserstory","promote issue to userstory",1),_this.rootscope.$broadcast("history:reload"),_this.loadIssue()}}(this))},IssueDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;return ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.scope.project.is_issues_activated?this.navUrls.resolve("project-issues",ctx):this.navUrls.resolve("project",ctx)},IssueDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.issue_statuses,_this.scope.statusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.typeById=groupBy(project.issue_types,function(x){return x.id}),_this.scope.typeList=_.sortBy(project.issue_types,"order"),_this.scope.severityList=project.severities,_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.priorityList=project.priorities,_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},IssueDetailController.prototype.loadIssue=function(){return this.rs.issues.getByRef(this.scope.projectId,this.params.issueref).then(function(_this){return function(issue){var ctx;return _this.scope.issue=issue,_this.scope.issueId=issue.id,_this.scope.commentModel=issue,null!=_this.scope.issue.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.issue.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-issues-detail",ctx)),null!=_this.scope.issue.neighbors.next.ref?(ctx={project:_this.scope.project.slug,ref:_this.scope.issue.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-issues-detail",ctx)):void 0}}(this))},IssueDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadIssue()}}(this))},IssueDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("IssueDetailController",IssueDetailController),IssueStatusDisplayDirective=function(){var link,template;return template=_.template('\n <% if (status.is_closed) { %>\n Closed\n <% } else { %>\n Open\n <% } %>\n\n\n <%- status.name %>\n'),link=function($scope,$el,$attrs){var render;return render=function(issue){var html;return html=template({status:$scope.statusById[issue.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(issue){return null!=issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueStatusDisplay",IssueStatusDisplayDirective),IssueStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- status.name %>\n <% if(editable){ %><% }%>\n status\n\n
      \n <% _.each(statuses, function(st) { %>\n
    • <%- st.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,status;return status=$scope.statusById[issue.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(value,issue){var onError,onSuccess;return onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save(value).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var issue,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),$.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.status=target.data("status-id"),$model.$setViewValue(issue),save($model.$modelValue,issue)):void 0 -}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",IssueStatusButtonDirective]),IssueTypeButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- type.name %>\n <% if(editable){ %><% }%>\n type\n\n
      \n <% _.each(typees, function(tp) { %>\n
    • <%- tp.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,type;return type=$scope.typeById[issue.type],html=template({type:type,typees:$scope.typeList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(type){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.type=type,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".type-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-type").popover().open():void 0}),$el.on("click",".type",function(event){var target,type;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),type=target.data("type-id"),save(type)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueTypeButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",IssueTypeButtonDirective]),IssueSeverityButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- severity.name %>\n <% if(editable){ %><% }%>\n severity\n\n
      \n <% _.each(severityes, function(sv) { %>\n
    • <%- sv.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,severity;return severity=$scope.severityById[issue.severity],html=template({severity:severity,severityes:$scope.severityList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(severity){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.severity=severity,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".severity-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-severity").popover().open():void 0}),$el.on("click",".severity",function(event){var severity,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),severity=target.data("severity-id"),save(severity)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueSeverityButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",IssueSeverityButtonDirective]),IssuePriorityButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- priority.name %>\n <% if(editable){ %><% }%>\n priority\n\n
      \n <% _.each(priorityes, function(pr) { %>\n
    • <%- pr.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,priority;return priority=$scope.priorityById[issue.priority],html=template({priority:priority,priorityes:$scope.priorityList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(priority){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.priority=priority,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".priority-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-priority").popover().open():void 0}),$el.on("click",".priority",function(event){var priority,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),priority=target.data("priority-id"),save(priority)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssuePriorityButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",IssuePriorityButtonDirective]),PromoteIssueToUsButtonDirective=function($rootScope,$repo,$confirm,$qqueue){var link,template;return template=_.template('\n Promote to User Story\n'),link=function($scope,$el,$attrs,$model){var save;return save=$qqueue.bindAdd(function(){return function(issue,finish){var data,onError,onSuccess;return data={generated_from_issue:issue.id,project:issue.project,subject:issue.subject,description:issue.description,tags:issue.tags,is_blocked:issue.is_blocked,blocked_note:issue.blocked_note},onSuccess=function(){return finish(),$confirm.notify("success"),$rootScope.$broadcast("promote-issue-to-us:success")},onError=function(){return finish(!1),$confirm.notify("error")},$repo.create("userstories",data).then(onSuccess,onError)}}(this)),$el.on("click","a",function(event){var issue,message,subtitle,title;return event.preventDefault(),issue=$model.$modelValue,title="Promote this issue to a new user story",message="Are you sure you want to create a new US from this Issue?",subtitle=issue.subject,$confirm.ask(title,subtitle,message).then(function(){return function(finish){return save(issue,finish)}}(this))}),$scope.$on("$destroy",function(){return $el.off()})},{restrict:"AE",require:"ngModel",template:template,link:link}},module.directive("tgPromoteIssueToUsButton",["$rootScope","$tgRepo","$tgConfirm","$tgQqueue",PromoteIssueToUsButtonDirective])}.call(this),function(){var CreateBulkIssuesDirective,CreateIssueDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaIssues"),CreateIssueDirective=function($repo,$confirm,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley(),$scope.issue={},$scope.$on("issueform:new",function(ctx,project){return $el.find(".tag-input").val(""),lightboxService.open($el),$scope.issue={project:project.id,subject:"",status:project.default_issue_status,type:project.default_issue_type,priority:project.default_priority,severity:project.default_severity,tags:[]}}),$scope.$on("$destroy",function(){return $el.off()}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("issues",$scope.issue),promise.then(function(data){return $loading.finish(submitButton),$rootscope.$broadcast("issueform:new:success",data),lightboxService.close($el),$confirm.notify("success")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLbCreateIssue",["$tgRepo","$tgConfirm","$rootScope","lightboxService","$tgLoading",CreateIssueDirective]),CreateBulkIssuesDirective=function($repo,$rs,$confirm,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.$on("issueform:bulk",function(ctx,projectId){return lightboxService.open($el),$scope["new"]={projectId:projectId,bulk:""}}),submit=debounce(2e3,function(){return function(event){var data,form,projectId,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),data=$scope["new"].bulk,projectId=$scope["new"].projectId,promise=$rs.issues.bulkCreate(projectId,data),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("issueform:new:success",result),lightboxService.close($el),$confirm.notify("success")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateBulkIssues",["$tgRepo","$tgResources","$tgConfirm","$rootScope","$tgLoading","lightboxService",CreateBulkIssuesDirective])}.call(this),function(){var IssueAssignedToInlineEditionDirective,IssueStatusInlineEditionDirective,IssuesController,IssuesDirective,IssuesFiltersDirective,bindOnce,debounceLeading,groupBy,joinStr,mixOf,module,paginatorTemplate,startswith,taiga,toString,trim,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounceLeading=this.taiga.debounceLeading,startswith=this.taiga.startswith,module=angular.module("taigaIssues"),IssuesController=function(_super){function IssuesController(scope,rootscope,repo,confirm,rs,urls,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var filters,promise;return this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.urls=urls,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,this.loadIssues=__bind(this.loadIssues,this),this.scope.sectionName="Issues",this.scope.filters={},_.isEmpty(this.location.search())?(filters=this.rs.issues.getFilters(this.params.pslug),filters.page=1,this.location.search(filters),void this.location.replace()):(promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Issues - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded),void this.scope.$on("issueform:new:success",function(_this){return function(){return _this.analytics.trackEvent("issue","create","create issue on issues list",1),_this.loadIssues(),_this.loadFilters()}}(this)))}return __extends(IssuesController,_super),IssuesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$tgUrls","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],IssuesController.prototype.initializeSubscription=function(){var routingKey;return routingKey="changes.project."+this.scope.projectId+".issues",this.events.subscribe(this.scope,routingKey,function(_this){return function(){return _this.loadIssues()}}(this))},IssuesController.prototype.storeFilters=function(){return this.rs.issues.storeFilters(this.params.pslug,this.location.search())},IssuesController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issueStatusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.issueStatusList=_.sortBy(project.issue_statuses,"order"),_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.severityList=_.sortBy(project.severities,"order"),_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.priorityList=_.sortBy(project.priorities,"order"),_this.scope.issueTypes=_.sortBy(project.issue_types,"order"),_this.scope.issueTypeById=groupBy(project.issue_types,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},IssuesController.prototype.getUrlFilters=function(){var filters;return filters=_.pick(this.location.search(),"page","tags","statuses","types","q","severities","priorities","assignedTo","createdBy","orderBy"),filters.page||(filters.page=1),filters},IssuesController.prototype.getUrlFilter=function(name){var filters;return filters=_.pick(this.location.search(),name),filters[name]},IssuesController.prototype.loadMyFilters=function(){return this.rs.issues.getMyFilters(this.scope.projectId).then(function(){return function(filters){return _.map(filters,function(value,key){return{id:key,name:key,type:"myFilters",selected:!1}})}}(this))},IssuesController.prototype.removeNotExistingFiltersFromUrl=function(){var currentSearch,existingValues,filterName,filterValue,splittedValues,urlfilters;currentSearch=this.location.search(),urlfilters=this.getUrlFilters();for(filterName in urlfilters)filterValue=urlfilters[filterName],"page"!==filterName&&"orderBy"!==filterName&&"q"!==filterName&&(splittedValues="tags"===filterName?_.map((""+filterValue).split(",")):_.map((""+filterValue).split(","),function(x){return"null"===x?null:parseInt(x)}),existingValues=_.intersection(splittedValues,_.map(this.scope.filters[filterName],"id")),splittedValues.length!==existingValues.length&&this.location.search(filterName,existingValues.join()));return currentSearch!==this.location.search()?this.location.replace():void 0},IssuesController.prototype.markSelectedFilters=function(filters,urlfilters){var isSelected,key,name,obj,searchdata,val,value,_i,_len,_ref,_ref1,_results;searchdata={},_ref=_.omit(urlfilters,"page","orderBy");for(name in _ref)for(value=_ref[name],null==searchdata[name]&&(searchdata[name]={}),_ref1=(""+value).split(","),_i=0,_len=_ref1.length;_len>_i;_i++)val=_ref1[_i],searchdata[name][val]=!0;isSelected=function(type,id){return null!=searchdata[type]&&searchdata[type][id]?!0:!1},_results=[];for(key in filters)value=filters[key],_results.push(function(){var _j,_len1,_results1;for(_results1=[],_j=0,_len1=value.length;_len1>_j;_j++)obj=value[_j],_results1.push(obj.selected=isSelected(obj.type,obj.id)?!0:void 0);return _results1}());return _results},IssuesController.prototype.loadFilters=function(){var promise,urlfilters;return urlfilters=this.getUrlFilters(),urlfilters.q&&(this.scope.filtersQ=urlfilters.q),promise=this.loadMyFilters().then(function(_this){return function(myFilters){return _this.scope.filters.myFilters=myFilters,myFilters}}(this)),promise=promise.then(function(_this){return function(){return _this.rs.issues.filtersData(_this.scope.projectId)}}(this)),promise.then(function(_this){return function(data){var choicesFiltersFormat,tagsFilterFormat,usersFiltersFormat;return usersFiltersFormat=function(users,type,unknownOption){var reformatedUsers,unknownItem;return reformatedUsers=_.map(users,function(t){return{id:t[0],count:t[1],type:type,name:t[0]?_this.scope.usersById[t[0]].full_name_display:unknownOption}}),unknownItem=_.remove(reformatedUsers,function(u){return!u.id}),reformatedUsers=_.sortBy(reformatedUsers,function(u){return u.name.toUpperCase()}),unknownItem.length>0&&reformatedUsers.unshift(unknownItem[0]),reformatedUsers},choicesFiltersFormat=function(choices,type,byIdObject){return _.map(choices,function(t){return{id:t[0],name:byIdObject[t[0]].name,color:byIdObject[t[0]].color,count:t[1],type:type}})},tagsFilterFormat=function(tags){return _.map(tags,function(t){return{id:t[0],name:t[0],color:_this.scope.project.tags_colors[t[0]],count:t[1],type:"tags"}})},_this.scope.filters.statuses=choicesFiltersFormat(data.statuses,"statuses",_this.scope.issueStatusById),_this.scope.filters.severities=choicesFiltersFormat(data.severities,"severities",_this.scope.severityById),_this.scope.filters.priorities=choicesFiltersFormat(data.priorities,"priorities",_this.scope.priorityById),_this.scope.filters.assignedTo=usersFiltersFormat(data.assigned_to,"assignedTo","Unassigned"),_this.scope.filters.createdBy=usersFiltersFormat(data.created_by,"createdBy","Unknown"),_this.scope.filters.types=choicesFiltersFormat(data.types,"types",_this.scope.issueTypeById),_this.scope.filters.tags=tagsFilterFormat(data.tags),_this.removeNotExistingFiltersFromUrl(),_this.markSelectedFilters(_this.scope.filters,urlfilters),_this.rootscope.$broadcast("filters:loaded",_this.scope.filters)}}(this))},IssuesController.prototype.loadIssuesRequests=0,IssuesController.prototype.loadIssues=function(){var name,promise,values,_ref;this.scope.urlFilters=this.getUrlFilters(),this.scope.httpParams={},_ref=this.scope.urlFilters;for(name in _ref)values=_ref[name],"severities"===name?name="severity":"orderBy"===name?name="order_by":"priorities"===name?name="priority":"assignedTo"===name?name="assigned_to":"createdBy"===name?name="owner":"statuses"===name?name="status":"types"===name&&(name="type"),this.scope.httpParams[name]=values;return promise=this.rs.issues.list(this.scope.projectId,this.scope.httpParams),this.loadIssuesRequests+=1,promise.index=this.loadIssuesRequests,promise.then(function(_this){return function(data){return promise.index===_this.loadIssuesRequests&&(_this.scope.issues=data.models,_this.scope.page=data.current,_this.scope.count=data.count,_this.scope.paginatedBy=data.paginatedBy),data}}(this))},IssuesController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription(),_this.q.all([_this.loadFilters(),_this.loadIssues()])}}(this))},IssuesController.prototype.saveCurrentFiltersTo=function(newFilter){var deferred;return deferred=this.q.defer(),this.rs.issues.getMyFilters(this.scope.projectId).then(function(_this){return function(filters){return filters[newFilter]=_this.location.search(),_this.rs.issues.storeMyFilters(_this.scope.projectId,filters).then(function(){return deferred.resolve()})}}(this)),deferred.promise},IssuesController.prototype.deleteMyFilter=function(filter){var deferred;return deferred=this.q.defer(),this.rs.issues.getMyFilters(this.scope.projectId).then(function(_this){return function(filters){return delete filters[filter],_this.rs.issues.storeMyFilters(_this.scope.projectId,filters).then(function(){return deferred.resolve()})}}(this)),deferred.promise},IssuesController.prototype.addNewIssue=function(){return this.rootscope.$broadcast("issueform:new",this.scope.project)},IssuesController.prototype.addIssuesInBulk=function(){return this.rootscope.$broadcast("issueform:bulk",this.scope.projectId)},IssuesController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("IssuesController",IssuesController),paginatorTemplate='
      \n <% if (showPrevious) { %>\n \n <% } %>\n\n <% _.each(pages, function(item) { %>\n
    • \n <% if (item.type === "page") { %>\n <%- item.num %>\n <% } else if (item.type === "page-active") { %>\n <%- item.num %>\n <% } else { %>\n ...\n <% } %>\n
    • \n <% }); %>\n\n <% if (showNext) { %>\n \n <% } %>\n
    ',IssuesDirective=function(){var link,linkOrdering,linkPagination,template;return template=_.template(paginatorTemplate),linkPagination=function($scope,$el,$attrs,$ctrl){var $pagEl,afterCurrent,atBegin,atEnd,beforeCurrent,getNumPages,renderPagination;return afterCurrent=2,beforeCurrent=4,atBegin=2,atEnd=2,$pagEl=$el.find(".issues-paginator"),getNumPages=function(){var numPages;return numPages=$scope.count/$scope.paginatedBy,numPages=parseInt(numPages,10)=numPages)return void $pagEl.hide();for($pagEl.show(),pages=[],options={},options.pages=pages,options.showPrevious=$scope.page>1,options.showNext=!($scope.page===numPages),cpage=$scope.page,i=_i=1;numPages>=1?numPages>=_i:_i>=numPages;i=numPages>=1?++_i:--_i)i===cpage+afterCurrent&&numPages>cpage+afterCurrent+atEnd?pages.push({classes:"dots",type:"dots"}):i===cpage-beforeCurrent&&cpage>atBegin+beforeCurrent?pages.push({classes:"dots",type:"dots"}):i>cpage+afterCurrent&&numPages-atEnd>=i||cpage-beforeCurrent>i&&i>atBegin||pages.push(i===cpage?{classes:"active",num:i,type:"page-active"}:{classes:"page",num:i,type:"page"});return $pagEl.html(template(options))},$scope.$watch("issues",function(value){return value?renderPagination():void 0}),$el.on("click",".issues-paginator a.next",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page+1),$ctrl.loadIssues()})}),$el.on("click",".issues-paginator a.previous",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page-1),$ctrl.loadIssues()})}),$el.on("click",".issues-paginator li.page > a",function(event){var pagenum,target;return event.preventDefault(),target=angular.element(event.currentTarget),pagenum=target.data("pagenum"),$scope.$apply(function(){return $ctrl.selectFilter("page",pagenum),$ctrl.loadIssues()})})},linkOrdering=function($scope,$el,$attrs,$ctrl){var colHeadElement,currentOrder,icon;return currentOrder=$ctrl.getUrlFilter("orderBy")||"created_date",currentOrder&&(icon=startswith(currentOrder,"-")?"icon-caret-up":"icon-caret-down",colHeadElement=$el.find(".row.title > div[data-fieldname='"+trim(currentOrder,"-")+"']"),colHeadElement.html(""+colHeadElement.html()+"")),$el.on("click",".row.title > div",function(event){var finalOrder,newOrder,target;return target=angular.element(event.currentTarget),currentOrder=$ctrl.getUrlFilter("orderBy"),newOrder=target.data("fieldname"),finalOrder=currentOrder===newOrder?"-"+newOrder:newOrder,$scope.$apply(function(){return $ctrl.replaceFilter("orderBy",finalOrder),$ctrl.storeFilters(),$ctrl.loadIssues().then(function(){return $el.find(".row.title > div > span.icon").remove(),icon=startswith(finalOrder,"-")?"icon-caret-up":"icon-caret-down",target.html(""+target.html()+"")})})})},link=function($scope,$el,$attrs){var $ctrl;return $ctrl=$el.controller(),linkOrdering($scope,$el,$attrs,$ctrl),linkPagination($scope,$el,$attrs,$ctrl),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssues",["$log","$tgLocation",IssuesDirective]),IssuesFiltersDirective=function($log,$location,$rs,$confirm,$loading){var link,template,templateSelected;return template=_.template('<% _.each(filters, function(f) { %>\n <% if (!f.selected) { %>\n \n style="border-left: 3px solid <%- f.color %>;"<% } %>>\n <%- f.name %>\n \n <% if (f.count){ %>\n <%- f.count %>\n <% } %>\n <% if (f.type == "myFilters"){ %>\n \n <% } %>\n \n <% } %>\n<% }) %>\n\n \n'),templateSelected=_.template('<% _.each(filters, function(f) { %>\n\n style="border-left: 3px solid <%- f.color %>;"<% } %>>\n <%- f.name %>\n \n \n\n<% }) %>'),link=function($scope,$el){var $ctrl,initializeSelectedFilters,renderFilters,renderSelectedFilters,selectQFilter,selectedFilters,showCategories,showFilters,toggleFilterSelection;return $ctrl=$el.closest(".wrapper").controller(),selectedFilters=[],showFilters=function(title,type){return $el.find(".filters-cats").hide(),$el.find(".filter-list").removeClass("hidden"),$el.find("h2.breadcrumb").removeClass("hidden"),$el.find("h2 a.subfilter span.title").html(title),$el.find("h2 a.subfilter span.title").prop("data-type",type)},showCategories=function(){return $el.find(".filters-cats").show(),$el.find(".filter-list").addClass("hidden"),$el.find("h2.breadcrumb").addClass("hidden")},initializeSelectedFilters=function(filters){var name,val,values,_i,_len;selectedFilters=[];for(name in filters)for(values=filters[name],_i=0,_len=values.length;_len>_i;_i++)val=values[_i],val.selected&&selectedFilters.push(val);return renderSelectedFilters(selectedFilters)},renderSelectedFilters=function(selectedFilters){var html;return html=templateSelected({filters:selectedFilters}),$el.find(".filters-applied").html(html),selectedFilters.length>0?$el.find(".save-filters").show():$el.find(".save-filters").hide()},renderFilters=function(filters){var html;return html=template({filters:filters}),$el.find(".filter-list").html(html)},toggleFilterSelection=function(type,id){var currentFiltersType,filter,filterId,filters;return"myFilters"===type?($rs.issues.getMyFilters($scope.projectId).then(function(data){var filters,myFilters;return myFilters=data,filters=myFilters[id],filters.page=1,$ctrl.replaceAllFilters(filters),$ctrl.storeFilters(),$ctrl.loadIssues(),$ctrl.markSelectedFilters($scope.filters,filters),initializeSelectedFilters($scope.filters)}),null):(filters=$scope.filters[type],filterId="tags"===type?taiga.toString(id):id,filter=_.find(filters,{id:filterId}),filter.selected=!filter.selected,null===id&&(id="null"),filter.selected?(selectedFilters.push(filter),$scope.$apply(function(){return $ctrl.selectFilter(type,id),$ctrl.selectFilter("page",1),$ctrl.storeFilters(),$ctrl.loadIssues()})):(selectedFilters=_.reject(selectedFilters,filter),$scope.$apply(function(){return $ctrl.unselectFilter(type,id),$ctrl.selectFilter("page",1),$ctrl.storeFilters(),$ctrl.loadIssues()})),renderSelectedFilters(selectedFilters),currentFiltersType=$el.find("h2 a.subfilter span.title").prop("data-type"),type===currentFiltersType?renderFilters(_.reject(filters,"selected")):void 0)},$scope.$on("filters:loaded",function(ctx,filters){return initializeSelectedFilters(filters)}),selectQFilter=debounceLeading(100,function(value){return void 0!==value?(0===value.length?($ctrl.replaceFilter("q",null),$ctrl.storeFilters()):($ctrl.replaceFilter("q",value),$ctrl.storeFilters()),$ctrl.loadIssues()):void 0}),$scope.$watch("filtersQ",selectQFilter),$el.on("click",".filters-cats > ul > li > a",function(event){var tags,target;return event.preventDefault(),target=angular.element(event.currentTarget),tags=$scope.filters[target.data("type")],renderFilters(_.reject(tags,"selected")),showFilters(target.attr("title"),target.data("type"))}),$el.on("click",".filters-inner > .filters-step-cat > .breadcrumb > .back",function(event){return event.preventDefault(),showCategories($el)}),$el.on("click",".filters-applied a",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),id=target.data("id")||null,type=target.data("type"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),target.toggleClass("active"),id=target.data("id")||null,type=target.data("type"),"myFilters"===type&&target.removeClass("active"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter .icon-delete",function(event){var customFilterName,message,target,title;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),customFilterName=target.parent().data("id"),title="Delete custom filter",message="the custom filter '"+customFilterName+"'",$confirm.askOnDelete(title,message).then(function(finish){var promise;return promise=$ctrl.deleteMyFilter(customFilterName),promise.then(function(){return promise=$ctrl.loadMyFilters(),promise.then(function(filters){return finish(),$scope.filters.myFilters=filters,renderFilters($scope.filters.myFilters)}),promise.then(null,function(){return finish()})}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})})}),$el.on("click",".save-filters",function(event){return event.preventDefault(),renderFilters($scope.filters.myFilters),showFilters("My filters","myFilters"),$el.find(".save-filters").hide(),$el.find(".my-filter-name").removeClass("hidden"),$el.find(".my-filter-name").focus() -}),$el.on("keyup",".new .my-filter-name",function(event){var newFilter,promise,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newFilter=target.val(),$loading.start($el.find(".new")),promise=$ctrl.saveCurrentFiltersTo(newFilter),promise.then(function(){var loadPromise;return loadPromise=$ctrl.loadMyFilters(),loadPromise.then(function(filters){var currentfilterstype;return $loading.finish($el.find(".new")),$scope.filters.myFilters=filters,currentfilterstype=$el.find("h2 a.subfilter span.title").prop("data-type"),"myFilters"===currentfilterstype&&renderFilters($scope.filters.myFilters),$el.find(".my-filter-name").addClass("hidden"),$el.find(".save-filters").show()}),loadPromise.then(null,function(){return $loading.finish($el.find(".new")),$confirm.notify("error","Error loading custom filters")})}),promise.then(null,function(){return $loading.finish($el.find(".new")),$el.find(".my-filter-name").val(newFilter).focus().select(),$confirm.notify("error","Filter not saved")})):27===event.keyCode?($el.find(".my-filter-name").val(""),$el.find(".my-filter-name").addClass("hidden"),$el.find(".save-filters").show()):void 0})},{link:link}},module.directive("tgIssuesFilters",["$log","$tgLocation","$tgResources","$tgConfirm","$tgLoading",IssuesFiltersDirective]),IssueStatusInlineEditionDirective=function($repo){var link,selectionTemplate,updateIssueStatus;return selectionTemplate=_.template(''),updateIssueStatus=function($el,issue,issueStatusById){var issueStatusDom,issueStatusDomParent,status;return issueStatusDomParent=$el.find(".issue-status"),issueStatusDom=$el.find(".issue-status .issue-status-bind"),status=issueStatusById[issue.status],status?(issueStatusDom.text(status.name),issueStatusDom.prop("title",status.name),issueStatusDomParent.css("color",status.color)):void 0},link=function($scope,$el,$attrs){var $ctrl,issue;return $ctrl=$el.controller(),issue=$scope.$eval($attrs.tgIssueStatusInlineEdition),$el.on("click",".issue-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",function(event){var target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),issue.status=target.data("status-id"),$el.find(".pop-status").popover().close(),updateIssueStatus($el,issue,$scope.issueStatusById),$scope.$apply(function(){return $repo.save(issue).then})}),taiga.bindOnce($scope,"project",function(project){return $el.append(selectionTemplate({statuses:project.issue_statuses})),updateIssueStatus($el,issue,$scope.issueStatusById),-1===project.my_permissions.indexOf("modify_issue")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$watch($attrs.tgIssueStatusInlineEdition,function(){return function(val){return updateIssueStatus($el,val,$scope.issueStatusById)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssueStatusInlineEdition",["$tgRepo",IssueStatusInlineEditionDirective]),IssueAssignedToInlineEditionDirective=function($repo,$rootscope){var link,template;return template=_.template('<%- name %>\n
    <%- name %>
    '),link=function($scope,$el,$attrs){var $ctrl,issue,updateIssue;return updateIssue=function(issue){var ctx,member;return ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=$scope.usersById[issue.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name_display),$el.find(".avatar").html(template(ctx)),$el.find(".issue-assignedto").attr("title",ctx.name)},$ctrl=$el.controller(),issue=$scope.$eval($attrs.tgIssueAssignedToInlineEdition),updateIssue(issue),$el.on("click",".issue-assignedto",function(){return $rootscope.$broadcast("assigned-to:add",issue)}),taiga.bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_issue")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("assigned-to:added",function(){return function(ctx,userId,updatedIssue){return updatedIssue.id===issue.id?(updatedIssue.assigned_to=userId,$repo.save(updatedIssue),updateIssue(updatedIssue)):void 0}}(this)),$scope.$watch($attrs.tgIssueAssignedToInlineEdition,function(){return function(val){return updateIssue(val)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssueAssignedToInlineEdition",["$tgRepo","$rootScope",IssueAssignedToInlineEditionDirective])}.call(this),function(){var UsClientRequirementButtonDirective,UsStatusButtonDirective,UsStatusDisplayDirective,UsTasksProgressDisplayDirective,UsTeamRequirementButtonDirective,UserStoryDetailController,bindOnce,groupBy,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaUserStories"),UserStoryDetailController=function(_super){function UserStoryDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.usRef=this.params.usref,this.scope.sectionName="User Story Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.us.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(UserStoryDetailController,_super),UserStoryDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],UserStoryDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("related-tasks:update",function(_this){return function(){return _this.loadUs(),_this.scope.tasks=_.clone(_this.scope.tasks,!1)}}(this)),this.scope.$on("attachment:create",function(_this){return function(){return _this.analytics.trackEvent("attachment","create","create attachment on userstory",1),_this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this))},UserStoryDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;return ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.navUrls.resolve("project",ctx),this.scope.project.is_backlog_activated?this.scope.us.milestone?(ctx.sprint=this.scope.sprint.slug,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-taskboard",ctx)):this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-backlog",ctx):this.scope.project.is_kanban_activated?this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-kanban",ctx):void 0},UserStoryDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.us_statuses,_this.scope.statusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.taskStatusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(_this.scope.pointsList,function(e){return e.id}),project}}(this))},UserStoryDetailController.prototype.loadUs=function(){return this.rs.userstories.getByRef(this.scope.projectId,this.params.usref).then(function(_this){return function(us){var ctx;return _this.scope.us=us,_this.scope.usId=us.id,_this.scope.commentModel=us,null!=_this.scope.us.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.us.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-userstories-detail",ctx)),null!=_this.scope.us.neighbors.next.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.us.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-userstories-detail",ctx)),us}}(this))},UserStoryDetailController.prototype.loadSprint=function(){return this.scope.us.milestone?this.rs.sprints.get(this.scope.us.project,this.scope.us.milestone).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,sprint}}(this)):void 0},UserStoryDetailController.prototype.loadTasks=function(){return this.rs.tasks.list(this.scope.projectId,null,this.scope.usId).then(function(_this){return function(tasks){return _this.scope.tasks=tasks,tasks}}(this))},UserStoryDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadUs().then(function(){return _this.q.all([_this.loadSprint(),_this.loadTasks()])})}}(this))},UserStoryDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserStoryDetailController",UserStoryDetailController),UsStatusDisplayDirective=function(){var link,template;return template=_.template('\n <% if (is_closed) { %>\n Closed\n <% } else { %>\n Open\n <% } %>\n\n\n <%- status.name %>\n'),link=function($scope,$el,$attrs){var render;return render=function(us){var html;return html=template({is_closed:us.is_closed,status:$scope.statusById[us.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(us){return null!=us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsStatusDisplay",UsStatusDisplayDirective),UsTasksProgressDisplayDirective=function(){var link,template;return template=_.template('
    \n\n <%- totalClosedTasks %>/<%- totalTasks %> tasks completed\n'),link=function($scope,$el,$attrs){var render;return render=function(tasks){var html,progress,totalClosedTasks,totalTasks;return totalTasks=tasks.length,totalClosedTasks=_.filter(tasks,function(){return function(task){return $scope.taskStatusById[task.status].is_closed}}(this)).length,progress=totalTasks>0?100*totalClosedTasks/totalTasks:0,html=template({totalTasks:totalTasks,totalClosedTasks:totalClosedTasks,progress:progress}),$el.html(html)},$scope.$watch($attrs.ngModel,function(tasks){return null!=tasks?render(tasks):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsTasksProgressDisplay",UsTasksProgressDisplayDirective),UsStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- status.name %>\n <% if(editable){ %><% }%>\n status\n\n
      \n <% _.each(statuses, function(st) { %>\n
    • <%- st.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(){return function(us){var html,status;return status=$scope.statusById[us.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(status){var onError,onSuccess,us;return us=$model.$modelValue.clone(),us.status=status,$.fn.popover().closeAll(),$model.$setViewValue(us),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),us.revert(),$model.$setViewValue(us),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var status,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),status=target.data("status-id"),save(status)):void 0}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",UsStatusButtonDirective]),UsTeamRequirementButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue){var link,template;return template=_.template('\n'),link=function($scope,$el,$attrs,$model){var canEdit,render,save;return canEdit=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var ctx,html;return canEdit()||us.team_requirement?(ctx={canEdit:canEdit(),isRequired:us.team_requirement},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(team_requirement){var promise,us;return us=$model.$modelValue.clone(),us.team_requirement=team_requirement,$model.$setViewValue(us),$loading.start($el.find("label")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $loading.finish($el.find("label")),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $loading.finish($el.find("label")),$confirm.notify("error"),us.revert(),$model.$setViewValue(us)})}}(this)),$el.on("click",".team-requirement",function(){var team_requirement;if(canEdit())return team_requirement=!$model.$modelValue.team_requirement,save(team_requirement)}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsTeamRequirementButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",UsTeamRequirementButtonDirective]),UsClientRequirementButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue){var link,template;return template=_.template('\n'),link=function($scope,$el,$attrs,$model){var canEdit,render,save;return canEdit=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var ctx,html;return canEdit()||us.client_requirement?(ctx={canEdit:canEdit(),isRequired:us.client_requirement},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(client_requirement){var promise,us;return us=$model.$modelValue.clone(),us.client_requirement=client_requirement,$model.$setViewValue(us),$loading.start($el.find("label")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $loading.finish($el.find("label")),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $loading.finish($el.find("label")),$confirm.notify("error"),us.revert(),$model.$setViewValue(us)})}}(this)),$el.on("click",".client-requirement",function(){var client_requirement;if(canEdit())return client_requirement=!$model.$modelValue.client_requirement,save(client_requirement)}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsClientRequirementButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",UsClientRequirementButtonDirective])}.call(this),function(){var TaskDetailController,TaskIsIocaineButtonDirective,TaskStatusButtonDirective,TaskStatusDisplayDirective,groupBy,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,module=angular.module("taigaTasks"),TaskDetailController=function(_super){function TaskDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.taskRef=this.params.taskref,this.scope.sectionName="Task Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.task.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TaskDetailController,_super),TaskDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],TaskDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("attachment:create",function(_this){return function(){return _this.analytics.trackEvent("attachment","create","create attachment on task",1),_this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this))},TaskDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;if(ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.navUrls.resolve("project",ctx),this.scope.project.is_backlog_activated){if(this.scope.task.milestone)return ctx.sprint=this.scope.sprint.slug,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-taskboard",ctx);if(this.scope.task.us)return ctx.ref=this.scope.us.ref,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-userstories-detail",ctx)}else if(this.scope.project.is_kanban_activated&&this.scope.us)return ctx.ref=this.scope.us.ref,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-userstories-detail",ctx)},TaskDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.task_statuses,_this.scope.statusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},TaskDetailController.prototype.loadTask=function(){return this.rs.tasks.getByRef(this.scope.projectId,this.params.taskref).then(function(_this){return function(task){var ctx;return _this.scope.task=task,_this.scope.taskId=task.id,_this.scope.commentModel=task,null!=_this.scope.task.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.task.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-tasks-detail",ctx)),null!=_this.scope.task.neighbors.next.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.task.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-tasks-detail",ctx)),task}}(this))},TaskDetailController.prototype.loadSprint=function(){return this.scope.task.milestone?this.rs.sprints.get(this.scope.task.project,this.scope.task.milestone).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,sprint}}(this)):void 0},TaskDetailController.prototype.loadUserStory=function(){return this.scope.task.user_story?this.rs.userstories.get(this.scope.task.project,this.scope.task.user_story).then(function(_this){return function(us){return _this.scope.us=us,us}}(this)):void 0},TaskDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadTask().then(function(){return _this.q.all([_this.loadSprint(),_this.loadUserStory()])})}}(this))},TaskDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TaskDetailController",TaskDetailController),TaskStatusDisplayDirective=function(){var link,template;return template=_.template('\n <% if (status.is_closed) { %>\n Closed\n <% } else { %>\n Open\n <% } %>\n\n\n <%- status.name %>\n'),link=function($scope,$el,$attrs){var render;return render=function(task){var html;return html=template({status:$scope.statusById[task.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(task){return null!=task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskStatusDisplay",TaskStatusDisplayDirective),TaskStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- status.name %>\n <% if(editable){ %><% }%>\n status\n\n
      \n <% _.each(statuses, function(st) { %>\n
    • <%- st.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_task")},render=function(){return function(task){var html,status;return status=$scope.statusById[task.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(status){var onError,onSuccess,task;return task=$model.$modelValue.clone(),task.status=status,$model.$setViewValue(task),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),task.revert(),$model.$setViewValue(task),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),$.fn.popover().closeAll(),save(target.data("status-id"))):void 0}),$scope.$watch($attrs.ngModel,function(task){return task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",TaskStatusButtonDirective]),TaskIsIocaineButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_task")},render=function(task){var ctx,html;return isEditable()||task.is_iocaine?(ctx={isIocaine:task.is_iocaine,isEditable:isEditable()},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(is_iocaine){var promise,task;return task=$model.$modelValue.clone(),task.is_iocaine=is_iocaine,$model.$setViewValue(task),$loading.start($el.find("label")),promise=$tgrepo.save(task),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return task.revert(),$model.$setViewValue(task),$confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find("label"))})}}(this)),$el.on("click",".is-iocaine",function(){var is_iocaine;if(isEditable())return is_iocaine=!$model.$modelValue.is_iocaine,save(is_iocaine)}),$scope.$watch($attrs.ngModel,function(task){return task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskIsIocaineButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",TaskIsIocaineButtonDirective])}.call(this),function(){var LeaveProjectDirective,TeamController,TeamFiltersDirective,TeamMemberCurrentUserDirective,TeamMemberStatsDirective,TeamMembersDirective,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,module=angular.module("taigaTeam"),TeamController=function(_super){function TeamController(scope,rootscope,repo,rs,params,q,location,navUrls,appTitle,auth,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.auth=auth,this.scope.sectionName="Team",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Team - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TeamController,_super),TeamController.$inject=["$scope","$rootScope","$tgRepo","$tgResources","$routeParams","$q","$location","$tgNavUrls","$appTitle","$tgAuth","tgLoader"],TeamController.prototype.setRole=function(role){return this.scope.filtersRole=role?role:""},TeamController.prototype.loadMembers=function(){return this.rs.memberships.list(this.scope.projectId,{},!1).then(function(_this){return function(data){var currentUser,membership,_i,_len,_ref;for(currentUser=_this.auth.getUser(),null==currentUser.photo&&(currentUser.photo="/images/unnamed.png"),_this.scope.currentUser=_.find(data,function(membership){return membership.user===currentUser.id}),_this.scope.totals={},_.forEach(data,function(membership){return _this.scope.totals[membership.user]=0}),_this.scope.memberships=_.filter(data,function(membership){return membership.user&&membership.user!==currentUser.id&&membership.is_user_active?membership:void 0}),_ref=_this.scope.memberships,_i=0,_len=_ref.length;_len>_i;_i++)membership=_ref[_i],null==membership.photo&&(membership.photo="/images/unnamed.png");return data}}(this))},TeamController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issuesEnabled=project.is_issues_activated,_this.scope.tasksEnabled=project.is_kanban_activated||project.is_backlog_activated,_this.scope.wikiEnabled=project.is_wiki_activated,project}}(this))},TeamController.prototype.loadMemberStats=function(){return this.rs.projects.memberStats(this.scope.projectId).then(function(_this){return function(stats){var totals;return totals={},_.forEach(_this.scope.totals,function(total,userId){var vals;return vals=_.map(stats,function(memberStats){return memberStats[userId]}),total=_.reduce(vals,function(sum,el){return sum+el}),_this.scope.totals[userId]=total}),_this.scope.stats=_this.processStats(stats),_this.scope.stats.totals=_this.scope.totals}}(this))},TeamController.prototype.processStat=function(stat){var max,min,singleStat;return max=_.max(stat),min=_.min(stat),singleStat=_.map(stat,function(value,key){return value===min?[key,.1]:value===max?[key,1]:[key,.5*value/max]}),singleStat=_.object(singleStat)},TeamController.prototype.processStats=function(stats){var key,value;for(key in stats)value=stats[key],stats[key]=this.processStat(value);return stats},TeamController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadMembers().then(function(){return _this.loadMemberStats()})}}(this))},TeamController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TeamController",TeamController),TeamFiltersDirective=function(){var template;return template='',{template:template} -},module.directive("tgTeamFilters",[TeamFiltersDirective]),TeamMemberStatsDirective=function(){var template;return template='
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    ',{template:template,scope:{stats:"=",userId:"=user",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamMemberStats",TeamMemberStatsDirective),TeamMemberCurrentUserDirective=function(){var template;return template='
    \n
    \n
    \n \n
    \n \n \n
    \n
    \n
    \n
    \n
    \n
    ',{template:template,scope:{projectId:"=projectid",currentUser:"=currentuser",stats:"=",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamCurrentUser",TeamMemberCurrentUserDirective),TeamMembersDirective=function(){var template;return template='
    \n
    \n
    \n \n
    \n \n \n
    \n
    \n
    \n
    \n
    ',{template:template,scope:{memberships:"=",filtersQ:"=filtersq",filtersRole:"=filtersrole",stats:"=",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamMembers",TeamMembersDirective),LeaveProjectDirective=function($repo,$confirm,$location,$rs,$navurls){var link,template;return template='\n Leave this project\n',link=function($scope,$el,$attrs){return $scope.leave=function(){return $confirm.ask("Leave this project","Are you sure you want to leave the project?").then(function(){return function(finish){var promise;return promise=$rs.projects.leave($attrs.projectid),promise.then(function(){return finish(),$confirm.notify("success"),$location.path($navurls.resolve("home"))}),promise.then(null,function(response){return finish(),$confirm.notify("error",response.data._error_message)})}}(this))}},{scope:{},template:template,link:link}},module.directive("tgLeaveProject",["$tgRepo","$tgConfirm","$tgLocation","$tgResources","$tgNavUrls",LeaveProjectDirective])}.call(this),function(){var EditableWikiContentDirective,WikiDetailController,WikiSummaryDirective,bindOnce,debounce,groupBy,mixOf,module,taiga,unslugify,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,unslugify=this.taiga.unslugify,debounce=this.taiga.debounce,module=angular.module("taigaWiki"),WikiDetailController=function(_super){function WikiDetailController(scope,rootscope,repo,model,confirm,rs,params,q,location,filter,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.model=model,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.filter=filter,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.projectSlug=this.params.pslug,this.scope.wikiSlug=this.params.slug,this.scope.sectionName="Wiki",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Wiki - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(WikiDetailController,_super),WikiDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgModel","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$filter","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],WikiDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},WikiDetailController.prototype.loadWiki=function(){var promise;return promise=this.rs.wiki.getBySlug(this.scope.projectId,this.params.slug),promise.then(function(_this){return function(wiki){return _this.scope.wiki=wiki,_this.scope.wikiId=wiki.id,_this.scope.wiki}}(this)),promise.then(null,function(_this){return function(){var data;return _this.scope.wikiId=null,-1===_this.scope.project.my_permissions.indexOf("add_wiki_page")?null:(data={project:_this.scope.projectId,slug:_this.scope.wikiSlug,content:""},_this.scope.wiki=_this.model.make_model("wiki",data),_this.scope.wiki)}}(this))},WikiDetailController.prototype.loadWikiLinks=function(){return this.rs.wiki.listLinks(this.scope.projectId).then(function(_this){return function(wikiLinks){return _this.scope.wikiLinks=wikiLinks}}(this))},WikiDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.q.all([_this.loadWikiLinks(),_this.loadWiki()])}}(this))},WikiDetailController.prototype["delete"]=function(){var message,title;return title="Delete Wiki Page",message=unslugify(this.scope.wiki.slug),this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var onError,onSuccess;return onSuccess=function(){var ctx;return finish(),ctx={project:_this.scope.projectSlug},_this.location.path(_this.navUrls.resolve("project-wiki",ctx)),_this.confirm.notify("success")},onError=function(){return finish(!1),_this.confirm.notify("error")},_this.repo.remove(_this.scope.wiki).then(onSuccess,onError)}}(this))},WikiDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("WikiDetailController",WikiDetailController),WikiSummaryDirective=function($log){var link,template;return template=_.template('
      \n
    • \n <%- totalEditions %>\n times
      edited
      \n
    • \n
    • \n <%- lastModifiedDate %>\n last
      edit
      \n
    • \n
    • \n
      \n <%- user.name %>\n
      \n last modification\n <%- user.name %>\n
    • \n
    '),link=function($scope,$el,$attrs){var render;return render=function(wiki){var ctx,html,user;return null==$scope.usersById?$log.error("WikiSummaryDirective requires userById set in scope."):user=$scope.usersById[wiki.last_modifier],user=void 0===user?{name:"unknown",imgUrl:"/images/unnamed.png"}:{name:user.full_name_display,imgUrl:user.photo},ctx={totalEditions:wiki.editions,lastModifiedDate:moment(wiki.modified_date).format("DD MMM YYYY HH:mm"),user:user},html=template(ctx),$el.html(html)},$scope.$watch($attrs.ngModel,function(wikiPage){return wikiPage?render(wikiPage):void 0}),$scope.$on("wiki:edit",function(event,wikiPage){return render(wikiPage)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgWikiSummary",["$log",WikiSummaryDirective]),EditableWikiContentDirective=function($window,$document,$repo,$confirm,$loading,$location,$navUrls,$analytics,$qqueue){var link,template;return template='
    \n
    \n \n
    \n',link=function($scope,$el,$attrs,$model){var cancelEdition,disableEdition,getSelectedText,isEditable,save,switchToEditMode,switchToReadMode;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_wiki_page")},switchToEditMode=function(){return $el.find(".edit-wiki-content").show(),$el.find(".view-wiki-content").hide(),$el.find("textarea").focus()},switchToReadMode=function(){return $el.find(".edit-wiki-content").hide(),$el.find(".view-wiki-content").show()},disableEdition=function(){return $el.find(".view-wiki-content .edit").remove(),$el.find(".edit-wiki-content").remove()},cancelEdition=function(){var ctx;if($scope.wiki.html)return $scope.wiki.id?($scope.$apply(function(){return function(){return $scope.wiki.revert()}}(this)),switchToReadMode()):(ctx={project:$scope.projectSlug},$location.path($navUrls.resolve("project-wiki",ctx)))},getSelectedText=function(){return $window.getSelection?$window.getSelection().toString():$document.selection?$document.selection.createRange().text:null},save=$qqueue.bindAdd(function(wiki){var onError,onSuccess,promise;return onSuccess=function(wikiPage){return null==wiki.id&&$analytics.trackEvent("wikipage","create","create wiki page",1),$scope.wiki=wikiPage,$model.setModelValue=wiki,$confirm.notify("success"),switchToReadMode(),$scope.$broadcast("wiki:edit",wikiPage)},onError=function(){return $confirm.notify("error")},$loading.start($el.find(".save-container")),promise=null!=wiki.id?$repo.save(wiki).then(onSuccess,onError):$repo.create("wiki",wiki).then(onSuccess,onError),promise["finally"](function(){return $loading.finish($el.find(".save-container"))})}),$el.on("mousedown",".view-wiki-content",function(event){var target;return target=angular.element(event.target),target.is("pre")?target.data("scroll-pos",target[0].scrollLeft):void 0}),$el.on("mouseup",".view-wiki-content",function(event){var prevPos,target;return target=angular.element(event.target),!isEditable()||target.is("a")||getSelectedText()||target.is("pre")&&(prevPos=target.data("scroll-pos"),target.data("scroll-pos",null),prevPos!==target[0].scrollLeft)?void 0:switchToEditMode()}),$el.on("click",".save",debounce(2e3,function(){return save($scope.wiki)})),$el.on("click",".cancel",function(){return cancelEdition()}),$el.on("keydown","textarea",function(event){return 27===event.keyCode?cancelEdition():void 0}),$scope.$watch($attrs.ngModel,function(wikiPage){return wikiPage?($scope.wiki=wikiPage,isEditable()?($el.addClass("editable"),null==wikiPage.id?switchToEditMode():void 0):disableEdition()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgEditableWikiContent",["$window","$document","$tgRepo","$tgConfirm","$tgLoading","$tgLocation","$tgNavUrls","$tgAnalytics","$tgQqueue",EditableWikiContentDirective])}.call(this),function(){var WikiNavDirective,bindOnce,groupBy,mixOf,module,slugify,taiga,unslugify;taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,slugify=this.taiga.slugify,unslugify=this.taiga.slugify,module=angular.module("taigaWiki"),WikiNavDirective=function($tgrepo,$log,$location,$confirm,$navUrls,$analytics,$loading){var link,template;return template=_.template('
    \n

    Links

    \n
    \n
    \n<% if (addWikiLinkPermission) { %>\nAdd link\n<% } %>'),link=function($scope,$el,$attrs){var $ctrl,render;return $ctrl=$el.controller(),null==$attrs.ngModel?$log.error("WikiNavDirective: no ng-model attr is defined"):(render=function(wikiLinks){var addWikiLinkPermission,deleteWikiLinkPermission,html;return addWikiLinkPermission=$scope.project.my_permissions.indexOf("add_wiki_link")>-1,deleteWikiLinkPermission=$scope.project.my_permissions.indexOf("delete_wiki_link")>-1,html=template({wikiLinks:wikiLinks,projectSlug:$scope.projectSlug,addWikiLinkPermission:addWikiLinkPermission,deleteWikiLinkPermission:deleteWikiLinkPermission}),$el.off(),$el.html(html),$el.on("click",".wiki-link .link-title",function(event){var linkId,linkSlug,target;return event.preventDefault(),target=angular.element(event.currentTarget),linkId=target.parents(".wiki-link").data("id"),linkSlug=$scope.wikiLinks[linkId].href,$scope.$apply(function(){var ctx;return ctx={project:$scope.projectSlug,slug:linkSlug},$location.path($navUrls.resolve("project-wiki-page",ctx))})}),$el.on("click",".add-button",function(event){return event.preventDefault(),$el.find(".new").removeClass("hidden"),$el.find(".new input").focus(),$el.find(".add-button").hide()}),$el.on("click",".wiki-link .icon-delete",function(event){var linkId,message,target,title;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),linkId=target.parents(".wiki-link").data("id"),title="Delete Wiki Link",message=$scope.wikiLinks[linkId].title,$confirm.askOnDelete(title,message).then(function(){return function(finish){var promise;return promise=$tgrepo.remove($scope.wikiLinks[linkId]),promise.then(function(){return promise=$ctrl.loadWikiLinks(),promise.then(function(){return finish(),render($scope.wikiLinks)}),promise.then(null,function(){return finish()})}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})}}(this))}),$el.on("keyup",".new input",function(event){var newLink,promise,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newLink=target.val(),$loading.start($el.find(".new")),promise=$tgrepo.create("wiki-links",{project:$scope.projectId,title:newLink,href:slugify(newLink)}),promise.then(function(){var loadPromise;return $analytics.trackEvent("wikilink","create","create wiki link",1),loadPromise=$ctrl.loadWikiLinks(),loadPromise.then(function(){return $loading.finish($el.find(".new")),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show(),render($scope.wikiLinks)}),loadPromise.then(null,function(){return $loading.finish($el.find(".new")),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show(),$confirm.notify("error","Error loading wiki links")})}),promise.then(null,function(error){var _ref;return $loading.finish($el.find(".new")),$el.find(".new input").val(newLink),$el.find(".new input").focus().select(),null!=(null!=error&&null!=(_ref=error.__all__)?_ref[0]:void 0)?$confirm.notify("error","The link already exists"):$confirm.notify("error")})):27===event.keyCode?(target=angular.element(event.currentTarget),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show()):void 0})},bindOnce($scope,$attrs.ngModel,render))},{link:link}},module.directive("tgWikiNav",["$tgRepo","$log","$tgLocation","$tgConfirm","$tgNavUrls","$tgAnalytics","$tgLoading",WikiNavDirective])}.call(this),function(){var CreateMembersDirective,MAX_MEMBERSHIP_FIELDSETS,debounce,module,taiga;taiga=this.taiga,debounce=this.taiga.debounce,module=angular.module("taigaKanban"),MAX_MEMBERSHIP_FIELDSETS=4,CreateMembersDirective=function($rs,$rootScope,$confirm,$loading,lightboxService){var extraTextTemplate,link,template;return extraTextTemplate='
    \n \n
    ',template=_.template('
    \n
    \n data-required="true" <% } %> data-type="email" />\n
    \n
    \n \n \n
    \n
    '),link=function($scope,$el){var createFieldSet,resetForm,submit,submitButton;return createFieldSet=function(required){var ctx;return null==required&&(required=!0),ctx={roleList:$scope.roles,required:required},template(ctx)},resetForm=function(){var fieldSet,invitations;return $el.find("form textarea").remove(""),$el.find("form .add-member-wrapper").remove(),invitations=$el.find(".add-member-forms"),invitations.html(extraTextTemplate),fieldSet=createFieldSet(),invitations.prepend(fieldSet)},$scope.$on("membersform:new",function(){return resetForm(),lightboxService.open($el)}),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click",".delete-fieldset",function(event){var fieldSet,lastActionButton,target;return event.preventDefault(),target=angular.element(event.currentTarget),fieldSet=target.closest(".add-member-wrapper"),fieldSet.remove(),lastActionButton=$el.find("fieldset:last > a"),lastActionButton.hasClass("icon-delete delete-fieldset")?lastActionButton.removeClass("icon-delete delete-fieldset").addClass("icon-plus add-fieldset"):void 0}),$el.on("click",".add-fieldset",function(event){var fieldSet,newFieldSet,target;return event.preventDefault(),target=angular.element(event.currentTarget),fieldSet=target.closest(".add-member-wrapper"),target.removeClass("icon-plus add-fieldset").addClass("icon-delete delete-fieldset"),newFieldSet=createFieldSet(!1),fieldSet.after(newFieldSet),$el.find(".add-member-wrapper").length===MAX_MEMBERSHIP_FIELDSETS?$el.find(".add-member-wrapper fieldset:last > a").removeClass("icon-plus add-fieldset").addClass("icon-delete delete-fieldset"):void 0}),submit=debounce(2e3,function(){return function(event){var form,invitation_extra_text,invitations,memberWrappers,onError,onSuccess;return event.preventDefault(),$loading.start(submitButton),onSuccess=function(){return $loading.finish(submitButton),lightboxService.close($el),$confirm.notify("success"),$rootScope.$broadcast("membersform:new:success")},onError=function(){return $loading.finish(submitButton),lightboxService.close($el),$confirm.notify("error"),$rootScope.$broadcast("membersform:new:error")},form=$el.find("form").checksley(),form.destroy(),form.initialize(),form.validate()?(memberWrappers=$el.find("form .add-member-wrapper"),memberWrappers=_.filter(memberWrappers,function(mw){return angular.element(mw).find("input").hasClass("checksley-ok")}),invitations=_.map(memberWrappers,function(mw){var email,memberWrapper,role;return memberWrapper=angular.element(mw),email=memberWrapper.find("input"),role=memberWrapper.find("select"),{email:email.val(),role_id:role.val()}}),invitations.length?(invitation_extra_text=$el.find("form textarea").val(),$rs.memberships.bulkCreateMemberships($scope.project.id,invitations,invitation_extra_text).then(onSuccess,onError)):void 0):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLbCreateMembers",["$tgResources","$rootScope","$tgConfirm","$tgLoading","lightboxService",CreateMembersDirective])}.call(this),function(){var MembershipsController,MembershipsDirective,MembershipsRowActionsDirective,MembershipsRowAdminCheckboxDirective,MembershipsRowAvatarDirective,MembershipsRowRoleSelectorDirective,bindMethods,mixOf,module,paginatorTemplate,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindMethods=this.taiga.bindMethods,module=angular.module("taigaAdmin"),MembershipsController=function(_super){function MembershipsController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,analytics,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.analytics=analytics,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Manage Members",this.scope.project={},this.scope.filters={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Membership - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("membersform:new:success",function(_this){return function(){return _this.loadMembers(),_this.analytics.trackEvent("membership","create","create memberships on admin",1)}}(this))}return __extends(MembershipsController,_super),MembershipsController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAnalytics","$appTitle"],MembershipsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},MembershipsController.prototype.loadMembers=function(){var httpFilters;return httpFilters=this.getUrlFilters(),this.rs.memberships.list(this.scope.projectId,httpFilters).then(function(_this){return function(data){return _this.scope.memberships=_.filter(data.models,function(membership){return null===membership.user||membership.is_user_active}),_this.scope.page=data.current,_this.scope.count=data.count,_this.scope.paginatedBy=data.paginatedBy,data}}(this))},MembershipsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadMembers()}}(this))},MembershipsController.prototype.getUrlFilters=function(){var filters;return filters=_.pick(this.location.search(),"page"),filters.page||(filters.page=1),filters},MembershipsController.prototype.addNewMembers=function(){return this.rootscope.$broadcast("membersform:new")},MembershipsController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("MembershipsController",MembershipsController),paginatorTemplate='
      \n <% if (showPrevious) { %>\n \n <% } %>\n\n <% _.each(pages, function(item) { %>\n
    • \n <% if (item.type === "page") { %>\n <%- item.num %>\n <% } else if (item.type === "page-active") { %>\n <%- item.num %>\n <% } else { %>\n ...\n <% } %>\n
    • \n <% }); %>\n\n <% if (showNext) { %>\n \n <% } %>\n
    ',MembershipsDirective=function(){var link,linkPagination,template;return template=_.template(paginatorTemplate),linkPagination=function($scope,$el,$attrs,$ctrl){var $pagEl,afterCurrent,atBegin,atEnd,beforeCurrent,getNumPages,renderPagination;return afterCurrent=2,beforeCurrent=4,atBegin=2,atEnd=2,$pagEl=$el.find(".memberships-paginator"),getNumPages=function(){var numPages;return numPages=$scope.count/$scope.paginatedBy,numPages=parseInt(numPages,10)=numPages)return void $pagEl.hide();for(pages=[],options={},options.pages=pages,options.showPrevious=$scope.page>1,options.showNext=!($scope.page===numPages),cpage=$scope.page,i=_i=1;numPages>=1?numPages>=_i:_i>=numPages;i=numPages>=1?++_i:--_i)i===cpage+afterCurrent&&numPages>cpage+afterCurrent+atEnd?pages.push({classes:"dots",type:"dots"}):i===cpage-beforeCurrent&&cpage>atBegin+beforeCurrent?pages.push({classes:"dots",type:"dots"}):i>cpage+afterCurrent&&numPages-atEnd>=i||cpage-beforeCurrent>i&&i>atBegin||pages.push(i===cpage?{classes:"active",num:i,type:"page-active"}:{classes:"page",num:i,type:"page"});return $pagEl.html(template(options))},$scope.$watch("memberships",function(value){return value?renderPagination():void 0}),$el.on("click",".memberships-paginator a.next",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page+1),$ctrl.loadMembers()})}),$el.on("click",".memberships-paginator a.previous",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page-1),$ctrl.loadMembers()})}),$el.on("click",".memberships-paginator li.page > a",function(event){var pagenum,target;return event.preventDefault(),target=angular.element(event.currentTarget),pagenum=target.data("pagenum"),$scope.$apply(function(){return $ctrl.selectFilter("page",pagenum),$ctrl.loadMembers()})})},link=function($scope,$el,$attrs){var $ctrl;return $ctrl=$el.controller(),linkPagination($scope,$el,$attrs,$ctrl),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgMemberships",MembershipsDirective),MembershipsRowAvatarDirective=function($log){var link,template;return template=_.template('
    \n <%- full_name %>\n
    \n <%- full_name %>\n \n
    \n
    '),link=function($scope,$el,$attrs){var member,render;return render=function(member){var ctx,html;return ctx={full_name:member.full_name?member.full_name:"",email:member.user_email?member.user_email:member.email,imgurl:member.photo?member.photo:"/images/unnamed.png"},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowAvatar?$log.error("MembershipsRowAvatarDirective: the directive need a member"):(member=$scope.$eval($attrs.tgMembershipsRowAvatar),render(member),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowAvatar",["$log",MembershipsRowAvatarDirective]),MembershipsRowAdminCheckboxDirective=function($log,$repo,$confirm){var link,template;return template=_.template('
    \n \n
    \n Yes\n No\n
    '),link=function($scope,$el,$attrs){var html,member,render;return render=function(member){var ctx,html;return ctx={inputId:"is-admin-"+member.id},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowAdminCheckbox?$log.error("MembershipsRowAdminCheckboxDirective: the directive need a member"):(member=$scope.$eval($attrs.tgMembershipsRowAdminCheckbox),html=render(member),member.is_owner&&$el.find(":checkbox").prop("checked",!0),$el.on("click",":checkbox",function(){return function(event){var onError,onSuccess,target;return onSuccess=function(){return $confirm.notify("success")},onError=function(data){return member.revert(),$el.find(":checkbox").prop("checked",member.is_owner),$confirm.notify("error",data.is_owner[0])},target=angular.element(event.currentTarget),member.is_owner=target.prop("checked"),$repo.save(member).then(onSuccess,onError)}}(this)),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowAdminCheckbox",["$log","$tgRepo","$tgConfirm",MembershipsRowAdminCheckboxDirective]),MembershipsRowRoleSelectorDirective=function($log,$repo,$confirm){var link,template;return template=_.template(''),link=function($scope,$el,$attrs){var $ctrl,html,member,render;return render=function(member){var ctx,html;return ctx={roleList:$scope.roles,selectedRole:member.role},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowRoleSelector?$log.error("MembershipsRowRoleSelectorDirective: the directive need a member"):($ctrl=$el.controller(),member=$scope.$eval($attrs.tgMembershipsRowRoleSelector),html=render(member),$el.on("click","select",function(){return function(event){var newRole,onError,onSuccess,target;return onSuccess=function(){return $confirm.notify("success")},onError=function(){return $confirm.notify("error")},target=angular.element(event.currentTarget),newRole=parseInt(target.val(),10),member.role!==newRole?(member.role=newRole,$repo.save(member).then(onSuccess,onError)):void 0 -}}(this)),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowRoleSelector",["$log","$tgRepo","$tgConfirm",MembershipsRowRoleSelectorDirective]),MembershipsRowActionsDirective=function($log,$repo,$rs,$confirm){var activedTemplate,link,pendingTemplate;return activedTemplate=_.template('
    \n Active\n
    \n\n \n'),pendingTemplate=_.template('\n Pending\n \n\n\n \n'),link=function($scope,$el,$attrs){var $ctrl,member,render;return render=function(member){var html;return html=member.user?activedTemplate():pendingTemplate(),$el.html(html)},null==$attrs.tgMembershipsRowActions?$log.error("MembershipsRowActionsDirective: the directive need a member"):($ctrl=$el.controller(),member=$scope.$eval($attrs.tgMembershipsRowActions),render(member),$el.on("click",".pending",function(event){var onError,onSuccess;return event.preventDefault(),onSuccess=function(){return $confirm.notify("success","We've sent the invitationi again to '"+$scope.member.email+"'.")},onError=function(){return $confirm.notify("error","We haven't sent the invitation.")},$rs.memberships.resendInvitation($scope.member.id).then(onSuccess,onError)}),$el.on("click",".delete",function(event){var message,title;return event.preventDefault(),title="Delete member",message=member.user?member.full_name:"the invitation to "+member.email,$confirm.askOnDelete(title,message).then(function(finish){var onError,onSuccess;return onSuccess=function(){return finish(),$ctrl.loadMembers(),$confirm.notify("success",null,"We've deleted "+message+".")},onError=function(){return finish(!1),$confirm.notify("error",null,"We have not been able to delete "+message+".")},$repo.remove(member).then(onSuccess,onError)})}),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowActions",["$log","$tgRepo","$tgResources","$tgConfirm",MembershipsRowActionsDirective])}.call(this),function(){var AdminNavigationDirective,module;AdminNavigationDirective=function(){var link;return link=function($scope,$el,$attrs){var section;return section=$attrs.tgAdminNavigation,$el.find(".active").removeClass("active"),$el.find("#adminmenu-"+section+" a").addClass("active"),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaAdmin"),module.directive("tgAdminNavigation",AdminNavigationDirective)}.call(this),function(){var ProjectDefaultValuesDirective,ProjectModulesDirective,ProjectProfileController,ProjectProfileDirective,bindOnce,debounce,groupBy,joinStr,mixOf,module,taiga,toString,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaAdmin"),ProjectProfileController=function(_super){function ProjectProfileController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Project profile - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:loaded",function(_this){return function(){return _this.appTitle.set("Project profile - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this))}return __extends(ProjectProfileController,_super),ProjectProfileController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],ProjectProfileController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.scope.taskStatusList=_.sortBy(project.task_statuses,"order"),_this.scope.prioritiesList=_.sortBy(project.priorities,"order"),_this.scope.severitiesList=_.sortBy(project.severities,"order"),_this.scope.issueTypesList=_.sortBy(project.issue_types,"order"),_this.scope.issueStatusList=_.sortBy(project.issue_statuses,"order"),_this.scope.$emit("project:loaded",project),project}}(this))},ProjectProfileController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},ProjectProfileController.prototype.openDeleteLightbox=function(){return this.rootscope.$broadcast("deletelightbox:new",this.scope.project)},ProjectProfileController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("ProjectProfileController",ProjectProfileController),ProjectProfileDirective=function($repo,$confirm,$loading,$navurls,$location){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.save($scope.project),promise.then(function(){var newUrl;return $loading.finish(submitButton),$confirm.notify("success"),newUrl=$navurls.resolve("project-admin-project-profile-details",{project:$scope.project.slug}),$location.path(newUrl),$scope.$emit("project:loaded",$scope.project)}),promise.then(null,function(data){return $loading.finish(target),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgProjectProfile",["$tgRepo","$tgConfirm","$tgLoading","$tgNavUrls","$tgLocation",ProjectProfileDirective]),ProjectDefaultValuesDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.save($scope.project),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(data){return $loading.finish(target),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgProjectDefaultValues",["$tgRepo","$tgConfirm","$tgLoading",ProjectDefaultValuesDirective]),ProjectModulesDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit;return form=$el.find("form").checksley(),submit=function(){return function(){var promise,target;if(form.validate())return target=angular.element(".admin-functionalities a.button-green"),$loading.start(target),promise=$repo.save($scope.project),promise.then(function(){return $loading.finish(target),$confirm.notify("success"),$scope.$emit("project:loaded",$scope.project)}),promise.then(null,function(data){return $loading.finish(target),$confirm.notify("error",data._error_message)})}}(this),$el.on("submit","form",function(event){return event.preventDefault(),submit()}),$el.on("click",".admin-functionalities a.button-green",function(event){return event.preventDefault(),submit()}),$scope.$watch("isVideoconferenceActivated",function(isVideoconferenceActivated){return isVideoconferenceActivated?$el.find(".videoconference-attributes").removeClass("hidden"):($el.find(".videoconference-attributes").addClass("hidden"),$scope.project.videoconferences=null,$scope.project.videoconferences_salt="")}),$scope.$watch("project",function(project){return $scope.isVideoconferenceActivated=null!=project.videoconferences?!0:!1})},{link:link}},module.directive("tgProjectModules",["$tgRepo","$tgConfirm","$tgLoading",ProjectModulesDirective])}.call(this),function(){var ColorSelectionDirective,ProjectValuesController,ProjectValuesDirective,bindOnce,debounce,groupBy,joinStr,mixOf,module,taiga,toString,trim,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaAdmin"),ProjectValuesController=function(_super){function ProjectValuesController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.moveValue=__bind(this.moveValue,this),this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Project values - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("admin:project-values:move",this.moveValue)}return __extends(ProjectValuesController,_super),ProjectValuesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],ProjectValuesController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},ProjectValuesController.prototype.loadValues=function(){return this.rs[this.scope.resource].listValues(this.scope.projectId,this.scope.type).then(function(_this){return function(values){return _this.scope.values=values,_this.scope.maxValueOrder=_.max(values,"order").order,values}}(this))},ProjectValuesController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.q.all([_this.loadProject(),_this.loadValues()])}}(this))},ProjectValuesController.prototype.moveValue=function(ctx,itemValue,itemIndex){var r,values;return values=this.scope.values,r=values.indexOf(itemValue),values.splice(r,1),values.splice(itemIndex,0,itemValue),_.each(values,function(value,index){return value.order=index}),this.repo.saveAll(values)},ProjectValuesController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("ProjectValuesController",ProjectValuesController),ProjectValuesDirective=function($log,$repo,$confirm,$location,animationFrame){var link,linkDragAndDrop,linkValue;return linkDragAndDrop=function($scope,$el){var itemEl,newParentScope,oldParentScope,tdom;return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el.find(".sortable"),tdom.sortable({handle:".row.table-main.visualization",dropOnEmpty:!0,connectWith:".project-values-body",revert:400,axis:"y"}),tdom.on("sortstop",function(event,ui){var itemIndex,itemValue;return itemEl=ui.item,itemValue=itemEl.scope().value,itemIndex=itemEl.index(),$scope.$broadcast("admin:project-values:move",itemValue,itemIndex)}),$scope.$on("$destroy",function(){return $el.off()})},linkValue=function($scope,$el,$attrs){var $ctrl,cancel,goToBottomList,initializeNewValue,saveValue,submit,valueType;return $ctrl=$el.controller(),valueType=$attrs.type,initializeNewValue=function(){return $scope.newValue={name:"",is_closed:!1,is_archived:!1}},initializeNewValue(),goToBottomList=function(){return function(focus){var table;return null==focus&&(focus=!1),table=$el.find(".table-main"),$(document.body).scrollTop(table.offset().top+table.height()),focus?$(".new-value input").focus():void 0}}(this),submit=debounce(2e3,function(){return function(){var promise;return promise=$repo.save($scope.project),promise.then(function(){return $confirm.notify("success")}),promise.then(null,function(data){return $confirm.notify("error",data._error_message)})}}(this)),saveValue=debounce(2e3,function(target){var form,promise,value;return form=target.parents("form").checksley(),form.validate()?(value=target.scope().value,promise=$repo.save(value),promise.then(function(){return function(){var row;return row=target.parents(".row.table-main"),row.addClass("hidden"),row.siblings(".visualization").removeClass("hidden")}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0}),cancel=function(target){var row,value;return row=target.parents(".row.table-main"),value=target.scope().value,$scope.$apply(function(){return row.addClass("hidden"),value.revert(),row.siblings(".visualization").removeClass("hidden")})},$el.on("submit","form",function(event){return event.preventDefault(),submit()}),$el.on("click","form a.button-green",function(event){return event.preventDefault(),submit()}),$el.on("click",".show-add-new",function(event){return event.preventDefault(),$el.find(".new-value").removeClass("hidden"),goToBottomList(!0)}),$el.on("click",".add-new",debounce(2e3,function(event){var form,promise;return event.preventDefault(),form=$el.find(".new-value").parents("form").checksley(),form.validate()?($scope.newValue.project=$scope.project.id,$scope.newValue.order=$scope.maxValueOrder?$scope.maxValueOrder+1:1,promise=$repo.create(valueType,$scope.newValue),promise.then(function(){return function(){return $ctrl.loadValues().then(function(){return animationFrame.add(function(){return goToBottomList()})}),$el.find(".new-value").addClass("hidden"),initializeNewValue()}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0})),$el.on("click",".delete-new",function(event){return event.preventDefault(),$el.find(".new-value").hide(),initializeNewValue()}),$el.on("click",".edit-value",function(event){var editionRow,row,target;return event.preventDefault(),target=angular.element(event.currentTarget),row=target.parents(".row.table-main"),row.addClass("hidden"),editionRow=row.siblings(".edition"),editionRow.removeClass("hidden"),editionRow.find("input:visible").first().focus().select()}),$el.on("keyup",".edition input",function(event){var target;return 13===event.keyCode?(target=angular.element(event.currentTarget),saveValue(target)):27===event.keyCode?(target=angular.element(event.currentTarget),cancel(target)):void 0}),$el.on("click",".save",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),saveValue(target)}),$el.on("click",".cancel",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),cancel(target)}),$el.on("click",".delete-value",function(event){var choices,replacement,subtitle,target,title,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.scope().value,choices={},_.each($scope.values,function(option){return value.id!==option.id?choices[option.id]=option.name:void 0}),title="Delete value",subtitle=value.name,replacement="All items with this value will be changed to",0===_.keys(choices).length?$confirm.error("You can't delete all values."):$confirm.askChoice(title,subtitle,choices,replacement).then(function(response){var onError,onSucces;return onSucces=function(){return $ctrl.loadValues()["finally"](function(){return response.finish()})},onError=function(){return $confirm.notify("error")},$repo.remove(value,{moveTo:response.selected}).then(onSucces,onError)})})},link=function($scope,$el,$attrs){return linkDragAndDrop($scope,$el,$attrs),linkValue($scope,$el,$attrs),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgProjectValues",["$log","$tgRepo","$tgConfirm","$tgLocation","animationFrame",ProjectValuesDirective]),ColorSelectionDirective=function(){var link;return link=function($scope,$el,$attrs,$model){var $ctrl;return $ctrl=$el.controller(),$scope.$watch($attrs.ngModel,function(element){return $scope.color=element.color}),$el.on("click",".current-color",function(event){var body,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),$el.find(".select-color").hide(),target.siblings(".select-color").show(),body=angular.element("body"),body.on("click",function(){return function(event){return 0===angular.element(event.target).parent(".select-color").length?($el.find(".select-color").hide(),body.unbind("click")):void 0}}(this))}),$el.on("click",".select-color .color",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $model.$modelValue.color=target.data("color")}),$el.find(".select-color").hide()}),$el.on("click",".select-color .selected-color",function(event){return event.preventDefault(),$scope.$apply(function(){return $model.$modelValue.color=$scope.color}),$el.find(".select-color").hide()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgColorSelection",ColorSelectionDirective)}.call(this),function(){var EditRoleDirective,NewRoleDirective,RolePermissionsDirective,RolesController,RolesDirective,bindMethods,bindOnce,debounce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child},__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1};taiga=this.taiga,mixOf=this.taiga.mixOf,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,bindMethods=this.taiga.bindMethods,module=angular.module("taigaAdmin"),RolesController=function(_super){function RolesController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Permissions",this.scope.project={},this.scope.anyComputableRole=!0,promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Roles - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(RolesController,_super),RolesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],RolesController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.anyComputableRole=_.some(_.map(project.roles,function(point){return point.computable})),project}}(this))},RolesController.prototype.loadRoles=function(){return this.rs.roles.list(this.scope.projectId).then(function(_this){return function(data){return _this.scope.roles=data,_this.scope.role=_this.scope.roles[0],data}}(this))},RolesController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadRoles()}}(this))},RolesController.prototype.setRole=function(role){return this.scope.role=role,this.scope.$broadcast("role:changed",this.scope.role)},RolesController.prototype["delete"]=function(){var choices,replacement,role,subtitle,title,warning,_i,_len,_ref;for(title="Delete Role",subtitle=this.scope.role.name,replacement="All the users with this role will be moved to",warning="Be careful, all role estimations will be removed",choices={},_ref=this.scope.roles,_i=0,_len=_ref.length;_len>_i;_i++)role=_ref[_i],role.id!==this.scope.role.id&&(choices[role.id]=role.name);return 0===_.keys(choices).length?this.confirm.error("You can't delete all values."):this.confirm.askChoice(title,subtitle,choices,replacement,warning).then(function(_this){return function(response){var promise;return promise=_this.repo.remove(_this.scope.role,{moveTo:response.selected}),promise.then(function(){return _this.loadProject(),_this.loadRoles()["finally"](function(){return response.finish()})}),promise.then(null,function(){return _this.confirm.notify("error")})}}(this))},RolesController.prototype.setComputable=debounce(2e3,function(){var onError,onSuccess;return onSuccess=function(_this){return function(){return _this.confirm.notify("success"),_this.loadProject()}}(this),onError=function(_this){return function(){return _this.confirm.notify("error"),_this.scope.role.revert()}}(this),this.repo.save(this.scope.role).then(onSuccess,onError)}),RolesController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("RolesController",RolesController),EditRoleDirective=function($repo,$confirm){var link;return link=function($scope,$el){var submit,toggleView;return toggleView=function(){return $el.find(".total").toggle(),$el.find(".edit-role").toggle()},submit=function(){var promise;return $scope.role.name=$el.find("input").val(),promise=$repo.save($scope.role),promise.then(function(){return $confirm.notify("success")}),promise.then(null,function(){return $confirm.notify("error")}),toggleView()},$el.on("click","a.icon-edit",function(){return toggleView(),$el.find("input").focus(),$el.find("input").val($scope.role.name)}),$el.on("click","a.save",submit),$el.on("keyup","input",function(event){return 13===event.keyCode?submit():27===event.keyCode?toggleView():void 0}),$scope.$on("role:changed",function(){return $el.find(".edit-role").is(":visible")?toggleView():void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgEditRole",["$tgRepo","$tgConfirm",EditRoleDirective]),RolesDirective=function(){var link;return link=function($scope,$el){var $ctrl;return $ctrl=$el.controller(),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRoles",RolesDirective),NewRoleDirective=function($tgrepo,$confirm){var DEFAULT_PERMISSIONS,link;return DEFAULT_PERMISSIONS=["view_project","view_milestones","view_us","view_tasks","view_issues"],link=function($scope,$el){var $ctrl;return $ctrl=$el.controller(),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click","a.add-button",function(event){return event.preventDefault(),$el.find(".new").removeClass("hidden"),$el.find(".new").focus(),$el.find(".add-button").hide()}),$el.on("keyup",".new",function(event){var newRole,onError,onSuccess,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newRole={project:$scope.projectId,name:target.val(),permissions:DEFAULT_PERMISSIONS,order:_.max($scope.roles,function(r){return r.order}).order+1,computable:!1},$el.find(".new").addClass("hidden"),$el.find(".new").val(""),onSuccess=function(role){return $scope.roles.push(role),$ctrl.setRole(role),$el.find(".add-button").show(),$ctrl.loadProject()},onError=function(){return $confirm.notify("error")},$tgrepo.create("roles",newRole).then(onSuccess,onError)):27===event.keyCode?(target=angular.element(event.currentTarget),$el.find(".new").addClass("hidden"),$el.find(".new").val(""),$el.find(".add-button").show()):void 0})},{link:link}},module.directive("tgNewRole",["$tgRepo","$tgConfirm",NewRoleDirective]),RolePermissionsDirective=function($rootscope,$repo,$confirm){var baseTemplate,categoryTemplate,link,resumeTemplate;return resumeTemplate=_.template('
    <%- category.name %>
    \n
    \n
    <%- category.activePermissions %>/<%- category.permissions.length %>
    \n <% _.each(category.permissions, function(permission) { %>\n
    \n <% }) %>\n
    \n
    '),categoryTemplate=_.template('
    \n
    \n
    \n
    \n
    \n <% _.each(category.permissions, function(permission) { %>\n
    \n <%- permission.description %>\n
    \n checked="checked"<% } %>/>\n
    \n Yes\n No\n
    \n
    \n <% }) %>\n
    \n
    \n
    '),baseTemplate=_.template('
    '),link=function($scope,$el,$attrs){var $ctrl,generateCategoriesFromRole,renderCategory,renderPermissions,renderResume;return $ctrl=$el.controller(),generateCategoriesFromRole=function(role){var categories,issuePermissions,milestonePermissions,setActivePermissions,setActivePermissionsPerCategory,taskPermissions,userStoryPermissions,wikiPermissions;return setActivePermissions=function(permissions){return _.map(permissions,function(x){var _ref;return _.extend({},x,{active:(_ref=x.key,__indexOf.call(role.permissions,_ref)>=0)})})},setActivePermissionsPerCategory=function(category){return _.map(category,function(x){return _.extend({},x,{activePermissions:_.filter(x.permissions,"active").length})})},categories=[],milestonePermissions=[{key:"view_milestones",description:"View sprints"},{key:"add_milestone",description:"Add sprint"},{key:"modify_milestone",description:"Modify sprint"},{key:"delete_milestone",description:"Delete sprint"}],categories.push({name:"Sprints",permissions:setActivePermissions(milestonePermissions)}),userStoryPermissions=[{key:"view_us",description:"View user story"},{key:"add_us",description:"Add user story"},{key:"modify_us",description:"Modify user story"},{key:"delete_us",description:"Delete user story"}],categories.push({name:"User Stories",permissions:setActivePermissions(userStoryPermissions)}),taskPermissions=[{key:"view_tasks",description:"View tasks"},{key:"add_task",description:"Add task"},{key:"modify_task",description:"Modify task"},{key:"delete_task",description:"Delete task"}],categories.push({name:"Tasks",permissions:setActivePermissions(taskPermissions)}),issuePermissions=[{key:"view_issues",description:"View issues"},{key:"add_issue",description:"Add issue"},{key:"modify_issue",description:"Modify issue"},{key:"delete_issue",description:"Delete issue"}],categories.push({name:"Issues",permissions:setActivePermissions(issuePermissions)}),wikiPermissions=[{key:"view_wiki_pages",description:"View wiki pages"},{key:"add_wiki_page",description:"Add wiki page"},{key:"modify_wiki_page",description:"Modify wiki page"},{key:"delete_wiki_page",description:"Delete wiki page"},{key:"view_wiki_links",description:"View wiki links"},{key:"add_wiki_link",description:"Add wiki link"},{key:"delete_wiki_link",description:"Delete wiki link"}],categories.push({name:"Wiki",permissions:setActivePermissions(wikiPermissions)}),setActivePermissionsPerCategory(categories)},renderResume=function(element,category){return element.find(".resume").html(resumeTemplate({category:category}))},renderCategory=function(category,index){var html;return html=categoryTemplate({category:category,index:index}),html=angular.element(html),renderResume(html,category),html},renderPermissions=function(){var html;return $el.off(),html=baseTemplate(),_.each(generateCategoriesFromRole($scope.role),function(category,index){return html=angular.element(html).append(renderCategory(category,index))}),$el.html(html),$el.on("click",".resume",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.next().toggleClass("open")}),$el.on("change",".category-item input",function(event){var getActivePermissions,onError,onSuccess,target;return getActivePermissions=function(){var activePermissions;return activePermissions=_.filter($el.find(".category-item input"),function(t){return angular.element(t).is(":checked")}),activePermissions=_.sortBy(_.map(activePermissions,function(t){var permission;return permission=angular.element(t).parents(".category-item").data("id")})),activePermissions.push("view_project"),activePermissions},target=angular.element(event.currentTarget),$scope.role.permissions=getActivePermissions(),onSuccess=function(role){var categories,categoryId;return categories=generateCategoriesFromRole(role),categoryId=target.parents(".category-config").data("id"),renderResume(target.parents(".category-config"),categories[categoryId]),$rootscope.$broadcast("projects:reload"),$confirm.notify("success"),$ctrl.loadProject()},onError=function(){return $confirm.notify("error"),target.prop("checked",!target.prop("checked")),$scope.role.permissions=getActivePermissions()},$repo.save($scope.role).then(onSuccess,onError)})},$scope.$on("$destroy",function(){return $el.off()}),$scope.$on("role:changed",function(){return renderPermissions()}),bindOnce($scope,$attrs.ngModel,renderPermissions)},{link:link}},module.directive("tgRolePermissions",["$rootScope","$tgRepo","$tgConfirm",RolePermissionsDirective])}.call(this),function(){var BitbucketController,BitbucketWebhooksDirective,GithubController,GithubWebhooksDirective,GitlabController,GitlabWebhooksDirective,SelectInputText,ValidOriginIpsDirective,bindMethods,debounce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindMethods=this.taiga.bindMethods,debounce=this.taiga.debounce,module=angular.module("taigaAdmin"),GithubController=function(_super){function GithubController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Github",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Github - "+_this.scope.project.name) -}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(GithubController,_super),GithubController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],GithubController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"github").then(function(_this){return function(github){return _this.scope.github=github}}(this))},GithubController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},GithubController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},GithubController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("GithubController",GithubController),GitlabController=function(_super){function GitlabController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Gitlab",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Gitlab - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:modules:reload",function(_this){return function(){return _this.loadModules()}}(this))}return __extends(GitlabController,_super),GitlabController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],GitlabController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"gitlab").then(function(_this){return function(gitlab){return _this.scope.gitlab=gitlab}}(this))},GitlabController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},GitlabController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},GitlabController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("GitlabController",GitlabController),BitbucketController=function(_super){function BitbucketController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Bitbucket",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Bitbucket - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:modules:reload",function(_this){return function(){return _this.loadModules()}}(this))}return __extends(BitbucketController,_super),BitbucketController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],BitbucketController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"bitbucket").then(function(_this){return function(bitbucket){return _this.scope.bitbucket=bitbucket}}(this))},BitbucketController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},BitbucketController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},BitbucketController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("BitbucketController",BitbucketController),SelectInputText=function(){var link;return link=function($scope,$el){return $el.on("click",".select-input-content",function(){return $el.find("input").select(),$el.find(".help-copy").addClass("visible")})},{link:link}},module.directive("tgSelectInputText",SelectInputText),GithubWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.github,"github"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgGithubWebhooks",["$tgRepo","$tgConfirm","$tgLoading",GithubWebhooksDirective]),GitlabWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.gitlab,"gitlab"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success"),$scope.$emit("project:modules:reload")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgGitlabWebhooks",["$tgRepo","$tgConfirm","$tgLoading",GitlabWebhooksDirective]),BitbucketWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.bitbucket,"bitbucket"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success"),$scope.$emit("project:modules:reload")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgBitbucketWebhooks",["$tgRepo","$tgConfirm","$tgLoading",BitbucketWebhooksDirective]),ValidOriginIpsDirective=function(){var link;return link=function($scope,$el,$attrs,$ngModel){return $ngModel.$parsers.push(function(value){return value=$.trim(value),""===value?[]:value.split(",")})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgValidOriginIps",ValidOriginIpsDirective)}.call(this),function(){var CreateProject,DeleteProjectDirective,bindOnce,debounce,module,taiga,timeout;taiga=this.taiga,bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,debounce=this.taiga.debounce,module=angular.module("taigaProject"),CreateProject=function($rootscope,$repo,$confirm,$location,$navurls,$rs,$projectUrl,$loading,lightboxService,$cacheFactory){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit,submitButton;return $scope.data={},$scope.templates=[],form=$el.find("form").checksley({onlyOneErrorElement:!0}),onSuccessSubmit=function(response){return $cacheFactory.get("$http").removeAll(),$loading.finish(submitButton),$rootscope.$broadcast("projects:reload"),$confirm.notify("success","Success"),$location.url($projectUrl.get(response)),lightboxService.close($el)},onErrorSubmit=function(response){var error_field,error_step,selectors,_i,_len,_ref;for($loading.finish(submitButton),form.setErrors(response),selectors=[],_ref=_.keys(response),_i=0,_len=_ref.length;_len>_i;_i++)error_field=_ref[_i],selectors.push("[name="+error_field+"]");return $el.find(".active").removeClass("active"),error_step=$el.find(selectors.join(",")).first().parents(".wizard-step"),error_step.addClass("active"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(error_step.data("step"))},submit=function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("projects",$scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this),$scope.$on("projects:create",function(){return $scope.data={total_story_points:100,total_milestones:5},$scope.templates.length?$scope.data.creation_template=_.head(_.filter($scope.templates,function(x){return"scrum"===x.slug})).id:$rs.projects.templates().then(function(){return function(result){return $scope.templates=result,$scope.data.creation_template=_.head(_.filter($scope.templates,function(x){return"scrum"===x.slug})).id}}(this)),$el.find(".active").removeClass("active"),$el.find(".create-step1").addClass("active"),lightboxService.open($el),timeout(600,function(){return $el.find(".progress-bar").addClass("step1")})}),$el.on("click",".button-next",function(event){var current,field,next,step,valid,_i,_len,_ref;for(event.preventDefault(),current=$el.find(".active"),valid=!0,_ref=form.fields,_i=0,_len=_ref.length;_len>_i;_i++)field=_ref[_i],current.find("[name="+field.element.attr("name")+"]").length&&(valid=field.validate()!==!1&&valid);return valid?(next=current.next(),current.toggleClass("active"),next.toggleClass("active"),step=next.data("step"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(step)):void 0}),$el.on("click",".button-prev",function(event){var current,prev,step;return event.preventDefault(),current=$el.find(".active"),prev=current.prev(),current.toggleClass("active"),prev.toggleClass("active"),step=prev.data("step"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(step)}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".close",function(event){return event.preventDefault(),lightboxService.close($el)})},{link:link}},module.directive("tgLbCreateProject",["$rootScope","$tgRepo","$tgConfirm","$location","$tgNavUrls","$tgResources","$projectUrl","$tgLoading","lightboxService","$cacheFactory",CreateProject]),DeleteProjectDirective=function($repo,$rootscope,$auth,$location,$navUrls,$confirm,lightboxService,tgLoader){var link;return link=function($scope,$el){var projectToDelete,submit;return projectToDelete=null,$scope.$on("deletelightbox:new",function(ctx,project){return lightboxService.open($el),projectToDelete=project}),$scope.$on("$destroy",function(){return $el.off()}),submit=function(){var promise;return tgLoader.start(),lightboxService.close($el),promise=$repo.remove(projectToDelete),promise.then(function(){return tgLoader.pageLoaded(),$rootscope.$broadcast("projects:reload"),$location.path($navUrls.resolve("home")),$confirm.notify("success")}),promise.then(null,function(){return $confirm.notify("error"),lightboxService.close($el)})},$el.on("click",".button-red",function(event){return event.preventDefault(),lightboxService.close($el)}),$el.on("click",".button-green",function(event){return event.preventDefault(),submit()})},{link:link}},module.directive("tgLbDeleteProject",["$tgRepo","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","$tgConfirm","lightboxService","tgLoader",DeleteProjectDirective])}.call(this),function(){var ProjectController,ProjectsController,ProjectsListDirective,ProjectsPaginationDirective,bindOnce,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,module=angular.module("taigaProject"),bindOnce=this.taiga.bindOnce,ProjectsController=function(_super){function ProjectsController(scope,q,rs,rootscope,navUrls,auth,location,appTitle,projectUrl,tgLoader){var promise;this.scope=scope,this.q=q,this.rs=rs,this.rootscope=rootscope,this.navUrls=navUrls,this.auth=auth,this.location=location,this.appTitle=appTitle,this.projectUrl=projectUrl,this.appTitle.set("Projects"),this.auth.isAuthenticated()||this.location.path(this.navUrls.resolve("login")),this.user=this.auth.getUser(),this.projects=[],promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.scope.$emit("projects:loaded")}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(ProjectsController,_super),ProjectsController.$inject=["$scope","$q","$tgResources","$rootScope","$tgNavUrls","$tgAuth","$tgLocation","$appTitle","$projectUrl","tgLoader"],ProjectsController.prototype.loadInitialData=function(){return this.rs.projects.list().then(function(_this){return function(projects){var project,_i,_len;for(_this.projects={recents:projects.slice(0,8),all:projects},_i=0,_len=projects.length;_len>_i;_i++)project=projects[_i],project.url=_this.projectUrl.get(project);return projects}}(this))},ProjectsController.prototype.newProject=function(){return this.rootscope.$broadcast("projects:create")},ProjectsController.prototype.logout=function(){return this.auth.logout(),this.location.path(this.navUrls.resolve("login"))},ProjectsController}(taiga.Controller),module.controller("ProjectsController",ProjectsController),ProjectController=function(_super){function ProjectController(scope,rs,repo,params,q,rootscope,appTitle,location,navUrls){var promise;this.scope=scope,this.rs=rs,this.repo=repo,this.params=params,this.q=q,this.rootscope=rootscope,this.appTitle=appTitle,this.location=location,this.navUrls=navUrls,promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.project.name),_this.scope.$emit("regenerate:project-pagination")}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(ProjectController,_super),ProjectController.$inject=["$scope","$tgResources","$tgRepo","$routeParams","$q","$rootScope","$appTitle","$tgLocation","$tgNavUrls"],ProjectController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadPageData()}}(this)).then(function(_this){return function(){return _this.scope.$emit("project:loaded",_this.scope.project)}}(this))},ProjectController.prototype.loadPageData=function(){return this.q.all([this.loadProjectStats(),this.loadProject()])},ProjectController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,project}}(this))},ProjectController.prototype.loadProjectStats=function(){return this.rs.projects.stats(this.scope.projectId).then(function(_this){return function(stats){return _this.scope.stats=stats,stats}}(this))},ProjectController}(taiga.Controller),module.controller("ProjectController",ProjectController),ProjectsPaginationDirective=function(){var link;return link=function($scope,$el){var checkButtonVisibility,container,containerSize,hasNextPage,hasPagination,hasPrevPage,hide,nextBtn,nextPage,pageSize,prevBtn,prevPage,remove,render,visible;return prevBtn=$el.find(".v-pagination-previous"),nextBtn=$el.find(".v-pagination-next"),container=$el.find("ul"),pageSize=0,containerSize=0,render=function(){return pageSize=$el.find(".v-pagination-list").height(),container.find("li").length&&hasPagination()?(hasNextPage()?visible(nextBtn):hide(nextBtn),hasPrevPage()?visible(prevBtn):hide(prevBtn)):remove()},hasPagination=function(){return containerSize=container.height(),containerSize>pageSize},hasPrevPage=function(top){return null==top&&(top=-parseInt(container.css("top"),10)||0),0!==top},hasNextPage=function(top){return containerSize=container.height(),top||(top=-parseInt(container.css("top"),10)||0),containerSize>pageSize&&containerSize>top+pageSize},nextPage=function(callback){var lastLi,maxTop,newTop,top;return top=parseInt(container.css("top"),10),newTop=top-pageSize,lastLi=$el.find(".v-pagination-list li:last-child"),maxTop=-(lastLi.position().top+lastLi.outerHeight()-pageSize),maxTop>newTop&&(newTop=maxTop),container.animate({top:newTop},callback),newTop},prevPage=function(callback){var newTop,top;return top=parseInt(container.css("top"),10),newTop=top+pageSize,newTop>0&&(newTop=0),container.animate({top:newTop},callback),newTop},visible=function(element){return element.css("visibility","visible")},hide=function(element){return element.css("visibility","hidden")},checkButtonVisibility=function(){},remove=function(){return container.css("top",0),hide(prevBtn),hide(nextBtn)},$el.on("click",".v-pagination-previous",function(event){var newTop;return event.preventDefault(),container.is(":animated")?void 0:(visible(nextBtn),newTop=prevPage(),hasPrevPage(newTop)?void 0:hide(prevBtn))}),$el.on("click",".v-pagination-next",function(event){var newTop;return event.preventDefault(),container.is(":animated")?void 0:(visible(prevBtn),newTop=-nextPage(),hasNextPage(newTop)?void 0:hide(nextBtn))}),$scope.$on("regenerate:project-pagination",function(){return remove(),render()}),$(window).on("resize.projects-pagination",render),$scope.$on("$destroy",function(){return $(window).off("resize.projects-pagination")})},{link:link}},module.directive("tgProjectsPagination",["$timeout",ProjectsPaginationDirective]),ProjectsListDirective=function($compile){var link,template;return template=_.template('
    \n
    \n \n
    \n \n
    \n \n
    \n
    '),link=function($scope,$el){var render;return render=function(projects){return $el.html($compile(template({projects:projects}))($scope)),$scope.$emit("regenerate:project-pagination")},$scope.$watch("projects",function(projects){return null!=projects?render(projects):void 0})},{link:link}},module.directive("tgProjectsList",["$compile",ProjectsListDirective])}.call(this),function(){var BindHtmlDirective,BindOnceAltDirective,BindOnceBindDirective,BindOnceHrefDirective,BindOnceHtmlDirective,BindOnceRefDirective,BindOnceSrcDirective,BindOnceTitleDirective,BindTitleDirective,bindOnce,module;bindOnce=this.taiga.bindOnce,BindOnceBindDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoBind,function(val){return $el.text(val)})},{link:link}},BindOnceHtmlDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoHtml,function(val){return $el.html(val)})},{link:link}},BindOnceRefDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoRef,function(val){return $el.html("#"+val+" ")})},{link:link}},BindOnceSrcDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoSrc,function(val){return $el.attr("src",val)})},{link:link}},BindOnceHrefDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoHref,function(val){return $el.attr("href",val)})},{link:link}},BindOnceAltDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoAlt,function(val){return $el.attr("alt",val)})},{link:link}},BindOnceTitleDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoTitle,function(val){return $el.attr("title",val)})},{link:link}},BindTitleDirective=function(){var link;return link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgTitleHtml,function(val){return null!=val?$el.attr("title",val):void 0})},{link:link}},BindHtmlDirective=function(){var link;return link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgBindHtml,function(val){return null!=val?$el.html(val):void 0})},{link:link}},module=angular.module("taigaBase"),module.directive("tgBoBind",BindOnceBindDirective),module.directive("tgBoHtml",BindOnceHtmlDirective),module.directive("tgBoRef",BindOnceRefDirective),module.directive("tgBoSrc",BindOnceSrcDirective),module.directive("tgBoHref",BindOnceHrefDirective),module.directive("tgBoAlt",BindOnceAltDirective),module.directive("tgBoTitle",BindOnceTitleDirective),module.directive("tgBindTitle",BindTitleDirective),module.directive("tgBindHtml",BindHtmlDirective)}.call(this),function(){var ConfigurationService,module;ConfigurationService=function(){function ConfigurationService(){this.config=window.taigaConfig}return ConfigurationService.prototype.get=function(key,defaultValue){return null==defaultValue&&(defaultValue=null),_.has(this.config,key)?this.config[key]:defaultValue},ConfigurationService}(),module=angular.module("taigaBase"),module.service("$tgConfig",ConfigurationService)}.call(this),function(){var ContribController,module,taigaContribPlugins,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taigaContribPlugins=this.taigaContribPlugins=this.taigaContribPlugins||[],ContribController=function(_super){function ContribController(rootScope,scope,params,repo,rs,confirm,appTitle){var promise;this.rootScope=rootScope,this.scope=scope,this.params=params,this.repo=repo,this.rs=rs,this.confirm=confirm,this.appTitle=appTitle,this.scope.currentPlugin=_.first(_.where(taigaContribPlugins,{slug:this.params.plugin})),this.scope.pluginTemplate="contrib/"+this.scope.currentPlugin.slug,this.scope.projectSlug=this.params.pslug,this.scope.adminPlugins=_.where(this.rootScope.contribPlugins,{type:"admin"}),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.project.name)}}(this)),promise.then(null,function(_this){return function(){return _this.confirm.notify("error")}}(this))}return __extends(ContribController,_super),ContribController.$inject=["$rootScope","$scope","$routeParams","$tgRepo","$tgResources","$tgConfirm","$appTitle"],ContribController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.$broadcast("project:loaded",project),project}}(this))},ContribController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},ContribController}(taiga.Controller),module=angular.module("taigaBase"),module.controller("ContribController",ContribController)}.call(this),function(){var FiltersStorageService,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,FiltersStorageService=function(_super){function FiltersStorageService(storage,params){this.storage=storage,this.params=params}return __extends(FiltersStorageService,_super),FiltersStorageService.$inject=["$tgStorage","$routeParams"],FiltersStorageService.prototype.generateHash=function(components){return null==components&&(components=[]),components=_.map(components,function(x){return JSON.stringify(x)}),hex_sha1(components.join(":"))},FiltersStorageService}(taiga.Service)}.call(this),function(){var HttpService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,HttpService=function(_super){function HttpService(http,q,storage){this.http=http,this.q=q,this.storage=storage,HttpService.__super__.constructor.call(this)}return __extends(HttpService,_super),HttpService.$inject=["$http","$q","$tgStorage"],HttpService.prototype.headers=function(){var token;return token=this.storage.get("token"),token?{Authorization:"Bearer "+token}:{}},HttpService.prototype.request=function(options){return options.headers=_.merge({},options.headers||{},this.headers()),_.isPlainObject(options.data)&&(options.data=JSON.stringify(options.data)),this.http(options)},HttpService.prototype.get=function(url,params,options){return options=_.merge({method:"GET",url:url},options),params&&(options.params=params),this.request(options)},HttpService.prototype.post=function(url,data,params,options){return options=_.merge({method:"POST",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype.put=function(url,data,params,options){return options=_.merge({method:"PUT",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype.patch=function(url,data,params,options){return options=_.merge({method:"PATCH",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype["delete"]=function(url,data,params,options){return options=_.merge({method:"DELETE",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgHttp",HttpService)}.call(this),function(){var I18nDirective,I18nService,bindOnce,defaults,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,bindOnce=this.taiga.bindOnce,defaults={ns:"app",fallbackLng:"en",async:!1,lng:"en"},I18nService=function(_super){function I18nService(rootscope,localesEn){this.rootscope=rootscope,this.options=_.clone(defaults,!0),this.options.resStore={en:{app:localesEn}}}return __extends(I18nService,_super),I18nService.prototype.setLanguage=function(language){return i18n.setLng(language),this.rootscope.currentLang=language,this.rootscope.$broadcast("i18n:changeLang",language)},I18nService.prototype.initialize=function(){return i18n.init(this.options),this.rootscope.t=i18n.t},I18nService.prototype.t=function(path,opts){return i18n.t(path,opts)},I18nService}(taiga.Service),I18nDirective=function($rootscope,$i18n){var link;return link=function($scope,$el,$attrs){var ns,options,opts,v,values,_i,_len,_ref,_results;for(values=$attrs.tr.split(","),options=$attrs.trOpts||"{}",opts=$scope.$eval(options),_results=[],_i=0,_len=values.length;_len>_i;_i++)v=values[_i],-1===v.indexOf(":")?_results.push($el.html(_.escape($i18n.t(v,opts)))):(_ref=v.split(":"),ns=_ref[0],v=_ref[1],_results.push($el.attr(ns,_.escape($i18n.t(v,opts)))));return _results},{link:link,restrict:"A",scope:!1}},module=angular.module("taigaBase"),module.service("$tgI18n",["$rootScope","localesEn",I18nService]),module.directive("tr",["$rootScope","$tgI18n",I18nDirective])}.call(this),function(){var locationFactory,module;locationFactory=function($location,$route){return $location.noreload=function(scope){var lastRoute,un;return lastRoute=$route.current,un=scope.$on("$locationChangeSuccess",function(){return $route.current=lastRoute,un()}),$location},$location},module=angular.module("taigaBase"),module.factory("$tgLocation",["$location","$route","$rootScope",locationFactory])}.call(this),function(){var Model,ModelService,module,provider,taiga,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};Model=function(){function Model(name,data,dataTypes){this._attrs=data,this._name=name,this._dataTypes=dataTypes,this.setAttrs(data),this.initialize()}return Model.prototype.clone=function(){var instance;return instance=new Model(this._name,this._attrs,this._dataTypes),instance._modifiedAttrs=this._modifiedAttrs,instance._isModified=this._isModified,instance},Model.prototype.applyCasts=function(){var attrName,castMethod,castName,_ref,_results;_ref=this._dataTypes,_results=[];for(attrName in _ref)castName=_ref[attrName],castMethod=service.casts[castName],castMethod&&_results.push(this._attrs[attrName]=castMethod(this._attrs[attrName]));return _results},Model.prototype.getIdAttrName=function(){return"id"},Model.prototype.getName=function(){return this._name},Model.prototype.getAttrs=function(patch){return null==patch&&(patch=!1),null!=this._attrs.version&&(this._modifiedAttrs.version=this._attrs.version),patch?_.extend({},this._modifiedAttrs):_.extend({},this._attrs,this._modifiedAttrs)},Model.prototype.setAttrs=function(attrs){return this._attrs=attrs,this._modifiedAttrs={},this.applyCasts(),this._isModified=!1},Model.prototype.setAttr=function(name,value){return this._modifiedAttrs[name]=value,this._isModified=!0},Model.prototype.initialize=function(){var getter,self,setter;return self=this,getter=function(name){return function(){return"string"==typeof name&&"__"===name.substr(0,2)?self[name]:__indexOf.call(_.keys(self._modifiedAttrs),name)<0?self._attrs[name]:self._modifiedAttrs[name]}},setter=function(name){return function(value){return"string"==typeof name&&"__"===name.substr(0,2)?void(self[name]=value):void(self._attrs[name]!==value?(self._modifiedAttrs[name]=value,self._isModified=!0):delete self._modifiedAttrs[name])}},_.each(this._attrs,function(value,name){var options;return options={get:getter(name),set:setter(name),enumerable:!0,configurable:!0},Object.defineProperty(self,name,options)})},Model.prototype.serialize=function(){var data;return data={data:_.clone(this._attrs),name:this._name},JSON.stringify(data) -},Model.prototype.isModified=function(){return this._isModified},Model.prototype.isAttributeModified=function(attribute){return null!=this._modifiedAttrs[attribute]},Model.prototype.markSaved=function(){return this._isModified=!1,this._attrs=this.getAttrs(),this._modifiedAttrs={}},Model.prototype.revert=function(){return this._modifiedAttrs={},this._isModified=!1},Model.desSerialize=function(sdata){var ddata,model;return ddata=JSON.parse(sdata),model=new Model(ddata.url,ddata.data)},Model}(),taiga=this.taiga,ModelService=function(_super){function ModelService(q,urls,storage,http){this.q=q,this.urls=urls,this.storage=storage,this.http=http,ModelService.__super__.constructor.call(this)}return __extends(ModelService,_super),ModelService.$inject=["$q","$tgUrls","$tgStorage","$tgHttp"],ModelService}(taiga.Service),provider=function(){var service;return service={},service.make_model=function(name,data,cls,dataTypes){return null==cls&&(cls=Model),null==dataTypes&&(dataTypes={}),new cls(name,data,dataTypes)},service.cls=Model,service.casts={"int":function(value){return parseInt(value,10)},"float":function(value){return parseFloat(value,10)}},service},module=angular.module("taigaBase"),module.factory("$tgModel",["$q","$http","$tgUrls","$tgStorage",provider])}.call(this),function(){var NavigationUrlsDirective,NavigationUrlsService,bindOnce,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,module=angular.module("taigaBase"),NavigationUrlsService=function(_super){function NavigationUrlsService(){this.urls={}}return __extends(NavigationUrlsService,_super),NavigationUrlsService.prototype.update=function(urls){return this.urls=_.merge({},this.urls,urls||{})},NavigationUrlsService.prototype.formatUrl=function(url,ctx){var replacer;return null==ctx&&(ctx={}),replacer=function(match){return match=trim(match,":"),ctx[match]||"undefined"},url.replace(/(:\w+)/g,replacer)},NavigationUrlsService.prototype.resolve=function(name,ctx){var url;return url=this.urls[name],url?ctx?this.formatUrl(url,ctx):url:""},NavigationUrlsService}(taiga.Service),module.service("$tgNavUrls",NavigationUrlsService),NavigationUrlsDirective=function($navurls,$auth,$q,$location){var bindOnceP,link,parseNav;return bindOnceP=function($scope,attr){var defered;return defered=$q.defer(),bindOnce($scope,attr,function(v){return defered.resolve(v)}),defered.promise},parseNav=function(data,$scope){var name,params,promises,values,_ref;return _ref=_.map(data.split(":"),trim),name=_ref[0],params=_ref[1],params=params?_.map(params.split(","),trim):[],values=_.map(params,function(x){return trim(x.split("=")[1])}),promises=_.map(values,function(x){return bindOnceP($scope,x)}),$q.all(promises).then(function(){var item,key,options,value,_i,_len,_ref1;for(options={},_i=0,_len=params.length;_len>_i;_i++)item=params[_i],_ref1=_.map(item.split("="),trim),key=_ref1[0],value=_ref1[1],options[key]=$scope.$eval(value);return[name,options]})},link=function($scope,$el,$attrs){return $el.is("a")&&$el.attr("href","#"),$el.on("mouseenter",function(event){var target;return target=$(event.currentTarget),target.data("fullUrl")?void 0:parseNav($attrs.tgNav,$scope).then(function(result){var fullUrl,name,options,url,user;return name=result[0],options=result[1],user=$auth.getUser(),user&&(options.user=user.username),url=$navurls.resolve(name),fullUrl=$navurls.formatUrl(url,options),target.data("fullUrl",fullUrl),target.is("a")&&target.attr("href",fullUrl),$el.on("click",function(event){if(event.preventDefault(),target=$(event.currentTarget),!target.hasClass("noclick"))switch(fullUrl=target.data("fullUrl"),event.which){case 1:return $location.url(fullUrl),$scope.$apply();case 2:return window.open(fullUrl)}})})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgNav",["$tgNavUrls","$tgAuth","$q","$tgLocation",NavigationUrlsDirective])}.call(this),function(){var RepositoryService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,RepositoryService=function(_super){function RepositoryService(q,model,storage,http,urls){this.q=q,this.model=model,this.storage=storage,this.http=http,this.urls=urls,RepositoryService.__super__.constructor.call(this)}return __extends(RepositoryService,_super),RepositoryService.$inject=["$q","$tgModel","$tgStorage","$tgHttp","$tgUrls"],RepositoryService.prototype.resolveUrlForModel=function(model){var idAttrName;return idAttrName=model.getIdAttrName(),""+this.urls.resolve(model.getName())+"/"+model[idAttrName]},RepositoryService.prototype.resolveUrlForAttributeModel=function(model){return this.urls.resolve(model.getName(),model.parent)},RepositoryService.prototype.create=function(name,data,dataTypes,extraParams){var defered,promise,url;return null==dataTypes&&(dataTypes={}),null==extraParams&&(extraParams={}),defered=this.q.defer(),url=this.urls.resolve(name),promise=this.http.post(url,JSON.stringify(data)),promise.success(function(_this){return function(_data){return defered.resolve(_this.model.make_model(name,_data,null,dataTypes))}}(this)),promise.error(function(){return function(data){return defered.reject(data)}}(this)),defered.promise},RepositoryService.prototype.remove=function(model,params){var defered,promise,url;return null==params&&(params={}),defered=this.q.defer(),url=this.resolveUrlForModel(model),promise=this.http["delete"](url,{},params),promise.success(function(){return defered.resolve(model)}),promise.error(function(){return defered.reject(model)}),defered.promise},RepositoryService.prototype.saveAll=function(models,patch){var promises;return null==patch&&(patch=!0),promises=_.map(models,function(_this){return function(x){return _this.save(x,!0)}}(this)),this.q.all(promises)},RepositoryService.prototype.save=function(model,patch){var data,defered,promise,url;return null==patch&&(patch=!0),defered=this.q.defer(),!model.isModified()&&patch?(defered.resolve(model),defered.promise):(url=this.resolveUrlForModel(model),data=JSON.stringify(model.getAttrs(patch)),promise=patch?this.http.patch(url,data):this.http.put(url,data),promise.success(function(){return function(data){return model._isModified=!1,model._attrs=_.extend(model.getAttrs(),data),model._modifiedAttrs={},model.applyCasts(),defered.resolve(model)}}(this)),promise.error(function(data){return defered.reject(data)}),defered.promise)},RepositoryService.prototype.saveAttribute=function(model,attribute,patch){var data,defered,promise,url;return null==patch&&(patch=!0),defered=this.q.defer(),!model.isModified()&&patch?(defered.resolve(model),defered.promise):(url=this.resolveUrlForAttributeModel(model),data={},data[attribute]=model.getAttrs(),promise=patch?this.http.patch(url,data):this.http.put(url,data),promise.success(function(){return function(data){return model._isModified=!1,model._attrs=_.extend(model.getAttrs(),data),model._modifiedAttrs={},model.applyCasts(),defered.resolve(model)}}(this)),promise.error(function(data){return defered.reject(data)}),defered.promise)},RepositoryService.prototype.refresh=function(model){var defered,promise,url;return defered=this.q.defer(),url=this.resolveUrlForModel(model),promise=this.http.get(url),promise.success(function(data){return model._modifiedAttrs={},model._attrs=data,model._isModified=!1,model.applyCasts(),defered.resolve(model)}),promise.error(function(data){return defered.reject(data)}),defered.promise},RepositoryService.prototype.queryMany=function(name,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){return _.map(data.data,function(x){return _this.model.make_model(name,x)})}}(this))},RepositoryService.prototype.queryOneAttribute=function(name,id,attribute,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name,id),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){var model;return model=_this.model.make_model(name,data.data[attribute]),model.parent=id,model}}(this))},RepositoryService.prototype.queryOne=function(name,id,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),id&&(url=""+url+"/"+id),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){return _this.model.make_model(name,data.data)}}(this))},RepositoryService.prototype.queryOneRaw=function(name,id,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),id&&(url=""+url+"/"+id),httpOptions=_.merge({headers:{}},options),options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(){return function(data){return data.data}}(this))},RepositoryService.prototype.queryPaginated=function(name,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),httpOptions=_.merge({headers:{}},options),this.http.get(url,params,httpOptions).then(function(_this){return function(data){var headers,result;return headers=data.headers(),result={},result.models=_.map(data.data,function(x){return _this.model.make_model(name,x)}),result.count=parseInt(headers["x-pagination-count"],10),result.current=parseInt(headers["x-pagination-current"]||1,10),result.paginatedBy=parseInt(headers["x-paginated-by"],10),result}}(this))},RepositoryService.prototype.resolve=function(options){var cache,params;return params={},null!=options.pslug&&(params.project=options.pslug),null!=options.usref&&(params.us=options.usref),null!=options.taskref&&(params.task=options.taskref),null!=options.issueref&&(params.issue=options.issueref),null!=options.sslug&&(params.milestone=options.sslug),null!=options.wikipage&&(params.wikipage=options.wikipage),cache=!(options.wikipage||options.sslug),this.queryOneRaw("resolver",null,params,{cache:cache})},RepositoryService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgRepo",RepositoryService)}.call(this),function(){var StorageService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,StorageService=function(_super){function StorageService(){StorageService.__super__.constructor.call(this)}return __extends(StorageService,_super),StorageService.$inject=["$rootScope"],StorageService.prototype.get=function(key,_default){var serializedValue;return serializedValue=localStorage.getItem(key),null===serializedValue?_default||null:JSON.parse(serializedValue)},StorageService.prototype.set=function(key,val){return _.isObject(key)?_.each(key,function(_this){return function(val,key){return _this.set(key,val)}}(this)):localStorage.setItem(key,JSON.stringify(val))},StorageService.prototype.contains=function(key){var value;return value=this.get(key),null!==value},StorageService.prototype.remove=function(key){return localStorage.removeItem(key)},StorageService.prototype.clear=function(){return localStorage.clear()},StorageService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgStorage",StorageService)}.call(this),function(){var UrlsService,format,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};format=function(fmt,obj){return obj=_.clone(obj),fmt.replace(/%s/g,function(){return String(obj.shift())})},taiga=this.taiga,UrlsService=function(_super){function UrlsService(config){this.config=config,this.urls={},this.mainUrl=config.get("api")}return __extends(UrlsService,_super),UrlsService.$inject=["$tgConfig"],UrlsService.prototype.update=function(urls){return this.urls=_.merge(this.urls,urls)},UrlsService.prototype.resolve=function(){var args,name,url;if(args=_.toArray(arguments),0===args.length)throw Error("wrong arguments to setUrls");return name=args.slice(0,1)[0],url=format(this.urls[name],args.slice(1)),format("%s/%s",[_.str.rtrim(this.mainUrl,"/"),_.str.ltrim(url,"/")])},UrlsService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgUrls",UrlsService)}.call(this),function(){var module,resourceProvider,sizeFormat,taiga;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,resourceProvider=function($rootScope,$config,$urls,$model,$repo,$auth,$q){var service;return service={},service.list=function(urlName,objectId,projectId){var params;return params={object_id:objectId,project:projectId},$repo.queryMany(urlName,params)},service.create=function(urlName,projectId,objectId,file){var data,defered,maxFileSize,response,uploadComplete,uploadFailed,uploadProgress,xhr;return defered=$q.defer(),void 0===file?(defered.reject(null),defered.promise):(maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&file.size>maxFileSize?(response={status:413,data:{_error_message:"'"+file.name+"' ("+sizeFormat(file.size)+") is too heavy for our oompa loompas, try it with a smaller than ("+sizeFormat(maxFileSize)+")"}},defered.reject(response),defered.promise):(uploadProgress=function(){return function(evt){return $rootScope.$apply(function(){return file.status="in-progress",file.size=sizeFormat(evt.total),file.progressMessage="upload "+sizeFormat(evt.loaded)+" of "+sizeFormat(evt.total),file.progressPercent=""+Math.round(evt.loaded/evt.total*100)+"%"})}}(this),uploadComplete=function(){return function(evt){return $rootScope.$apply(function(){var data,model;file.status="done";try{data=JSON.parse(evt.target.responseText)}catch(_error){data={}}return model=$model.make_model(urlName,data),defered.resolve(model)})}}(this),uploadFailed=function(){return function(){return $rootScope.$apply(function(){return file.status="error",defered.reject("fail")})}}(this),data=new FormData,data.append("project",projectId),data.append("object_id",objectId),data.append("attached_file",file),xhr=new XMLHttpRequest,xhr.upload.addEventListener("progress",uploadProgress,!1),xhr.addEventListener("load",uploadComplete,!1),xhr.addEventListener("error",uploadFailed,!1),xhr.open("POST",$urls.resolve(urlName)),xhr.setRequestHeader("Authorization","Bearer "+$auth.getToken()),xhr.setRequestHeader("Accept","application/json"),xhr.send(data),defered.promise))},function(instance){return instance.attachments=service}},module=angular.module("taigaResources"),module.factory("$tgAttachmentsResourcesProvider",["$rootScope","$tgConfig","$tgUrls","$tgModel","$tgRepo","$tgAuth","$q",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$http,$urls){var service;return service={},service.get=function(type,objectId){return $repo.queryOneRaw("history/"+type,objectId)},service.deleteComment=function(type,objectId,activityId){var params,url;return url=$urls.resolve("history/"+type),url=""+url+"/"+objectId+"/delete_comment",params={id:activityId},$http.post(url,null,params).then(function(){return function(data){return data.data}}(this))},service.undeleteComment=function(type,objectId,activityId){var params,url;return url=$urls.resolve("history/"+type),url=""+url+"/"+objectId+"/undelete_comment",params={id:activityId},$http.post(url,null,params).then(function(){return function(data){return data.data}}(this))},function(instance){return instance.history=service}},module=angular.module("taigaResources"),module.factory("$tgHistoryResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(token){return $repo.queryOne("invitations",token)},function(instance){return instance.invitations=service}},module=angular.module("taigaResources"),module.factory("$tgInvitationsResourcesProvider",["$tgRepo",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage,$q){var filtersHashSuffix,hashSuffix,myFiltersHashSuffix,service;return service={},hashSuffix="issues-queryparams",filtersHashSuffix="issues-filters",myFiltersHashSuffix="issues-my-filters",service.get=function(projectId,issueId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("issues",issueId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("issues","by_ref?project="+projectId+"&ref="+ref)},service.list=function(projectId,filters,options){var params;return params={project:projectId},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryPaginated("issues",params,options)},service.bulkCreate=function(projectId,data){var params,url;return url=$urls.resolve("bulk-create-issues"),params={project_id:projectId,bulk_issues:data},$http.post(url,params)},service.stats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/issues_stats")},service.filtersData=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/issue_filters_data")},service.listValues=function(projectId,type){var params;return params={project:projectId},service.storeQueryParams(projectId,params),$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeFilters=function(projectSlug,params){var hash,ns;return ns=""+projectSlug+":"+filtersHashSuffix,hash=generateHash([projectSlug,ns]),$storage.set(hash,params)},service.getFilters=function(projectSlug){var hash,ns;return ns=""+projectSlug+":"+filtersHashSuffix,hash=generateHash([projectSlug,ns]),$storage.get(hash)||{}},service.storeMyFilters=function(projectId,myFilters){var deferred,hash,ns,promise,url;return deferred=$q.defer(),url=$urls.resolve("user-storage"),ns=""+projectId+":"+myFiltersHashSuffix,hash=generateHash([projectId,ns]),_.isEmpty(myFilters)?(promise=$http["delete"](""+url+"/"+hash,{key:hash,value:myFilters}),promise.then(function(){return deferred.resolve()}),promise.then(null,function(){return deferred.reject()})):(promise=$http.put(""+url+"/"+hash,{key:hash,value:myFilters}),promise.then(function(){return deferred.resolve()}),promise.then(null,function(){var innerPromise;return innerPromise=$http.post(""+url,{key:hash,value:myFilters}),innerPromise.then(function(){return deferred.resolve()}),innerPromise.then(null,function(){return deferred.reject()})})),deferred.promise},service.getMyFilters=function(projectId){var deferred,hash,ns,promise,url;return deferred=$q.defer(),url=$urls.resolve("user-storage"),ns=""+projectId+":"+myFiltersHashSuffix,hash=generateHash([projectId,ns]),promise=$http.get(""+url+"/"+hash),promise.then(function(data){return deferred.resolve(data.data.value)}),promise.then(null,function(){return deferred.resolve({})}),deferred.promise},function(instance){return instance.issues=service}},module=angular.module("taigaResources"),module.factory("$tgIssuesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage","$q",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($storage){var hashSuffixStatusColumnModes,hashSuffixStatusViewModes,service;return service={},hashSuffixStatusViewModes="kanban-statusviewmodels",hashSuffixStatusColumnModes="kanban-statuscolumnmodels",service.storeStatusViewModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusViewModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusViewModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusViewModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeStatusColumnModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusColumnModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},function(instance){return instance.kanban=service}},module=angular.module("taigaResources"),module.factory("$tgKanbanResourcesProvider",["$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$urls,$http){var service;return service={},service.render=function(projectId,content){var params,url;return(null==content||""===content)&&(content=" "),params={project_id:projectId,content:content},url=$urls.resolve("wiki"),$http.post(""+url+"/render",params).then(function(){return function(data){return data.data}}(this))},function(instance){return instance.mdrender=service}},module=angular.module("taigaResources"),module.factory("$tgMdRenderResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$http,$urls){var service;return service={},service.get=function(id){return $repo.queryOne("memberships",id)},service.list=function(projectId,filters,enablePagination){var options,params;return null==enablePagination&&(enablePagination=!0),params={project:projectId},params=_.extend({},params,filters||{}),enablePagination?$repo.queryPaginated("memberships",params):$repo.queryMany("memberships",params,options={enablePagination:enablePagination})},service.listByUser=function(userId,filters){var params;return params={user:userId},params=_.extend({},params,filters||{}),$repo.queryPaginated("memberships",params)},service.resendInvitation=function(id){var url;return url=$urls.resolve("memberships"),$http.post(""+url+"/"+id+"/resend_invitation",{})},service.bulkCreateMemberships=function(projectId,data,invitation_extra_text){var params,url;return url=$urls.resolve("bulk-create-memberships"),params={project_id:projectId,bulk_memberships:data,invitation_extra_text:invitation_extra_text},$http.post(url,params)},function(instance){return instance.memberships=service}},module=angular.module("taigaResources"),module.factory("$tgMembershipsResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider;resourceProvider=function($repo){var service;return service={},service.list=function(projectId,module){return $repo.queryOneAttribute("project-modules",projectId,module)},function(instance){return instance.modules=service}},module=angular.module("taigaResources"),module.factory("$tgModulesResourcesProvider",["$tgRepo",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(id){return $repo.queryOne("notify-policies",id)},service.list=function(filters){var params;return params=_.extend({},params,filters||{}),$repo.queryMany("notify-policies",params)},function(instance){return instance.notifyPolicies=service}},module=angular.module("taigaResources"),module.factory("$tgNotifyPoliciesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$http,$urls){var service;return service={},service.get=function(id){return $repo.queryOne("projects",id)},service.getBySlug=function(slug){return $repo.queryOne("projects","by_slug?slug="+slug)},service.list=function(){return $repo.queryMany("projects")},service.templates=function(){return $repo.queryMany("project-templates")},service.usersList=function(projectId){var params;return params={project:projectId},$repo.queryMany("users",params)},service.rolesList=function(projectId){var params;return params={project:projectId},$repo.queryMany("roles",params)},service.stats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/stats")},service.leave=function(projectId){var url;return url=""+$urls.resolve("projects")+"/"+projectId+"/leave",$http.post(url)},service.memberStats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/member_stats")},service.tagsColors=function(id){return $repo.queryOne("projects",""+id+"/tags_colors")},function(instance){return instance.projects=service}},module=angular.module("taigaResources"),module.factory("$tgProjectsResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(id){return $repo.queryOne("roles",id)},service.list=function(projectId){return $repo.queryMany("roles",{project:projectId})},function(instance){return instance.roles=service}},module=angular.module("taigaResources"),module.factory("$tgRolesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$urls,$http){var service;return service={},service["do"]=function(projectId,term){var params,url;return url=$urls.resolve("search"),params={project:projectId,text:term,get_all:!1},$http.get(url,params).then(function(data){return data.data})},function(instance){return instance.search=service}},module=angular.module("taigaResources"),module.factory("$tgSearchResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$model,$storage){var hashSuffixUserstories,service;return service={},hashSuffixUserstories="userstories-queryparams",service.get=function(projectId,sprintId){return $repo.queryOne("milestones",sprintId).then(function(sprint){var uses;return service.storeUserstoriesQueryParams(projectId,{milestone:sprintId}),uses=sprint.user_stories,uses=_.map(uses,function(u){return $model.make_model("userstories",u)}),sprint._attrs.user_stories=uses,sprint})},service.stats=function(projectId,sprintId){return $repo.queryOneRaw("milestones",""+sprintId+"/stats")},service.list=function(projectId,filters){var params;return params={project:projectId},params=_.extend({},params,filters||{}),$repo.queryMany("milestones",params).then(function(){return function(milestones){var m,uses,_i,_len;for(_i=0,_len=milestones.length;_len>_i;_i++)m=milestones[_i],uses=m.user_stories,uses=_.map(uses,function(u){return $model.make_model("userstories",u)}),m._attrs.user_stories=uses;return milestones}}(this))},service.storeUserstoriesQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixUserstories,hash=generateHash([projectId,ns]),$storage.set(hash,params)},function(instance){return instance.sprints=service}},module=angular.module("taigaResources"),module.factory("$tgSprintsResourcesProvider",["$tgRepo","$tgModel","$tgStorage",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage){var hashSuffix,hashSuffixStatusColumnModes,hashSuffixUsRowModes,service;return service={},hashSuffix="tasks-queryparams",hashSuffixStatusColumnModes="tasks-statuscolumnmodels",hashSuffixUsRowModes="tasks-usrowmodels",service.get=function(projectId,taskId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("tasks",taskId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("tasks","by_ref?project="+projectId+"&ref="+ref)},service.list=function(projectId,sprintId,userStoryId){var params;return null==sprintId&&(sprintId=null),null==userStoryId&&(userStoryId=null),params={project:projectId},sprintId&&(params.milestone=sprintId),userStoryId&&(params.user_story=userStoryId),service.storeQueryParams(projectId,params),$repo.queryMany("tasks",params)},service.bulkCreate=function(projectId,sprintId,usId,data){var params,url;return url=$urls.resolve("bulk-create-tasks"),params={project_id:projectId,sprint_id:sprintId,us_id:usId,bulk_tasks:data},$http.post(url,params).then(function(result){return result.data})},service.bulkUpdateTaskTaskboardOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-task-taskboard-order"),params={project_id:projectId,bulk_tasks:data},$http.post(url,params)},service.listValues=function(projectId,type){var params;return params={project:projectId},$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeStatusColumnModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusColumnModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeUsRowModes=function(projectId,sprintId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixUsRowModes,hash=generateHash([projectId,sprintId,ns]),$storage.set(hash,params)},service.getUsRowModes=function(projectId,sprintId){var hash,ns;return ns=""+projectId+":"+hashSuffixUsRowModes,hash=generateHash([projectId,sprintId,ns]),$storage.get(hash)||{}},function(instance){return instance.tasks=service}},module=angular.module("taigaResources"),module.factory("$tgTasksResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider,sizeFormat,taiga;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,resourceProvider=function($config,$repo,$http,$urls,$q){var service;return service={},service.changeAvatar=function(file){var data,defered,maxFileSize,options,response,url;return maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&file.size>maxFileSize?(response={status:413,data:{_error_message:"'"+file.name+"' ("+sizeFormat(file.size)+") is too heavy for our oompa loompas, try it with a smaller than ("+sizeFormat(maxFileSize)+")"}},defered=$q.defer(),defered.reject(response),defered.promise):(data=new FormData,data.append("avatar",file),options={transformRequest:angular.identity,headers:{"Content-Type":void 0}},url=""+$urls.resolve("users")+"/change_avatar",$http.post(url,data,{},options))},service.removeAvatar=function(){var url;return url=""+$urls.resolve("users")+"/remove_avatar",$http.post(url) -},service.changePassword=function(currentPassword,newPassword){var data,url;return url=""+$urls.resolve("users")+"/change_password",data={current_password:currentPassword,password:newPassword},$http.post(url,data)},function(instance){return instance.userSettings=service}},module=angular.module("taigaResources"),module.factory("$tgUserSettingsResourcesProvider",["$tgConfig","$tgRepo","$tgHttp","$tgUrls","$q",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage){var hashSuffix,service;return service={},hashSuffix="userstories-queryparams",service.get=function(projectId,usId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("userstories",usId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("userstories","by_ref?project="+projectId+"&ref="+ref)},service.listUnassigned=function(projectId,filters){var params;return params={project:projectId,milestone:"null"},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryMany("userstories",params)},service.listAll=function(projectId,filters){var params;return params={project:projectId},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryMany("userstories",params)},service.bulkCreate=function(projectId,status,bulk){var data,url;return data={project_id:projectId,status_id:status,bulk_stories:bulk},url=$urls.resolve("bulk-create-us"),$http.post(url,data)},service.bulkUpdateBacklogOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-backlog-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.bulkUpdateSprintOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-sprint-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.bulkUpdateKanbanOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-kanban-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.listValues=function(projectId,type){var params;return params={project:projectId},service.storeQueryParams(projectId,params),$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeShowTags=function(projectId,showTags){var hash;return hash=generateHash([projectId,"showTags"]),$storage.set(hash,showTags)},service.getShowTags=function(projectId){var hash;return hash=generateHash([projectId,"showTags"]),$storage.get(hash)||null},function(instance){return instance.userstories=service}},module=angular.module("taigaResources"),module.factory("$tgUserstoriesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(wikiId){return $repo.queryOne("wiki",wikiId)},service.getBySlug=function(projectId,slug){return $repo.queryOne("wiki","by_slug?project="+projectId+"&slug="+slug)},service.listLinks=function(projectId){return $repo.queryMany("wiki-links",{project:projectId})},function(instance){return instance.wiki=service}},module=angular.module("taigaResources"),module.factory("$tgWikiResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var UserChangePasswordController,UserChangePasswordDirective,debounce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,debounce=this.taiga.debounce,module=angular.module("taigaUserSettings"),UserChangePasswordController=function(_super){function UserChangePasswordController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,auth){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="Change Password",this.scope.project={},this.scope.user=this.auth.getUser(),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserChangePasswordController,_super),UserChangePasswordController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserChangePasswordController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserChangePasswordController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},UserChangePasswordController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserChangePasswordController",UserChangePasswordController),UserChangePasswordDirective=function($rs,$confirm,$loading){var link;return link=function($scope,$el){var submit,submitButton;return submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),$scope.newPassword1!==$scope.newPassword2?void $confirm.notify("error","The passwords dosn't match"):($loading.start(submitButton),promise=$rs.userSettings.changePassword($scope.currentPassword,$scope.newPassword1),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(response){return $loading.finish(submitButton),$confirm.notify("error",response.data._error_message)}))}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserChangePassword",["$tgResources","$tgConfirm","$tgLoading",UserChangePasswordDirective])}.call(this),function(){var DeleteUserDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaUserSettings"),DeleteUserDirective=function($repo,$rootscope,$auth,$location,$navUrls,lightboxService){var link;return link=function($scope,$el){var submit;return $scope.$on("deletelightbox:new",function(){return lightboxService.open($el)}),$scope.$on("$destroy",function(){return $el.off()}),submit=function(){var promise;return promise=$repo.remove($scope.user),promise.then(function(){return lightboxService.close($el),$auth.logout(),$location.path($navUrls.resolve("login"))}),promise.then(null,function(){return console.log("FAIL")})},$el.on("click",".button-red",function(event){return event.preventDefault(),lightboxService.close($el)}),$el.on("click",".button-green",debounce(2e3,function(event){return event.preventDefault(),submit()}))},{link:link,templateUrl:"/partials/views/modules/lightbox-delete-account.html"}},module.directive("tgLbDeleteUser",["$tgRepo","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","lightboxService",DeleteUserDirective])}.call(this),function(){var TaigaAvatarModelDirective,UserAvatarDirective,UserProfileDirective,UserSettingsController,debounce,mixOf,module,sizeFormat,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,sizeFormat=this.taiga.sizeFormat,module=angular.module("taigaUserSettings"),debounce=this.taiga.debounce,UserSettingsController=function(_super){function UserSettingsController(scope,rootscope,config,repo,confirm,rs,params,q,location,navUrls,auth){var maxFileSize,promise;this.scope=scope,this.rootscope=rootscope,this.config=config,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="User Profile",this.scope.project={},this.scope.user=this.auth.getUser(),maxFileSize=this.config.get("maxUploadFileSize",null),maxFileSize&&(this.scope.maxFileSizeMsg="[Max, size: "+sizeFormat(maxFileSize)),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserSettingsController,_super),UserSettingsController.$inject=["$scope","$rootScope","$tgConfig","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserSettingsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserSettingsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},UserSettingsController.prototype.openDeleteLightbox=function(){return this.rootscope.$broadcast("deletelightbox:new",this.scope.user)},UserSettingsController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserSettingsController",UserSettingsController),UserProfileDirective=function($confirm,$auth,$repo){var link;return link=function($scope,$el){var submit;return submit=debounce(2e3,function(){return function(event){var changeEmail,form,onError,onSuccess;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?(changeEmail=$scope.user.isAttributeModified("email"),onSuccess=function(){return $auth.setUser($scope.user),changeEmail?$confirm.success("Check your inbox!
    We have sent a mail to your account
    with the instructions to set your new address"):$confirm.notify("success")},onError=function(data){return form.setErrors(data),$confirm.notify("error",data._error_message)},$repo.save($scope.user).then(onSuccess,onError)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserProfile",["$tgConfirm","$tgAuth","$tgRepo",UserProfileDirective]),UserAvatarDirective=function($auth,$model,$rs,$confirm){var link;return link=function($scope,$el){var onError,onSuccess,showSizeInfo;return showSizeInfo=function(){return $el.find(".size-info").removeClass("hidden")},onSuccess=function(response){var user;return user=$model.make_model("users",response.data),$auth.setUser(user),$scope.user=user,$el.find(".overlay").hide(),$confirm.notify("success")},onError=function(response){return 413===response.status&&showSizeInfo(),$el.find(".overlay").hide(),$confirm.notify("error",response.data._error_message)},$el.on("click",".button.change",function(){return $el.find("#avatar-field").click()}),$el.on("change","#avatar-field",function(){return $scope.avatarAttachment?($el.find(".overlay").show(),$rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess,onError)):void 0}),$el.on("click","a.use-gravatar",function(){return $el.find(".overlay").show(),$rs.userSettings.removeAvatar().then(onSuccess,onError)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserAvatar",["$tgAuth","$tgModel","$tgResources","$tgConfirm",UserAvatarDirective]),TaigaAvatarModelDirective=function($parse){var link;return link=function($scope,$el,$attrs){var model,modelSetter;return model=$parse($attrs.tgAvatarModel),modelSetter=model.assign,$el.bind("change",function(){return $scope.$apply(function(){return modelSetter($scope,$el[0].files[0])})})},{link:link}},module.directive("tgAvatarModel",["$parse",TaigaAvatarModelDirective])}.call(this),function(){var UserSettingsNavigationDirective,module;UserSettingsNavigationDirective=function(){var link;return link=function($scope,$el,$attrs){var section;return section=$attrs.tgUserSettingsNavigation,$el.find(".active").removeClass("active"),$el.find("#usersettingsmenu-"+section+" a").addClass("active"),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaUserSettings"),module.directive("tgUserSettingsNavigation",UserSettingsNavigationDirective)}.call(this),function(){var UserNotificationsController,UserNotificationsDirective,UserNotificationsListDirective,bindOnce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindOnce=this.taiga.bindOnce,module=angular.module("taigaUserSettings"),UserNotificationsController=function(_super){function UserNotificationsController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,auth){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="Email Notifications",this.scope.project={},this.scope.user=this.auth.getUser(),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserNotificationsController,_super),UserNotificationsController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserNotificationsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserNotificationsController.prototype.loadNotifyPolicies=function(){return this.rs.notifyPolicies.list().then(function(_this){return function(notifyPolicies){return _this.scope.notifyPolicies=notifyPolicies,notifyPolicies}}(this))},UserNotificationsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadNotifyPolicies()}}(this))},UserNotificationsController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserNotificationsController",UserNotificationsController),UserNotificationsDirective=function(){var link;return link=function($scope,$el){return $scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserNotifications",UserNotificationsDirective),UserNotificationsListDirective=function($repo,$confirm){var link,template;return template=_.template('<% _.each(notifyPolicies, function (notifyPolicy, index) { %>\n
    \n
    <%- notifyPolicy.project_name %>
    \n
    \n
    \n checked="checked"<% } %>/>\n \n
    \n
    \n
    \n
    \n checked="checked"<% } %> />\n \n
    \n
    \n
    \n
    \n checked="checked"<% } %> />\n \n
    \n
    \n
    \n<% }) %>'),link=function($scope,$el,$attrs){var render;return render=function(){return $el.off(),$el.html(template({notifyPolicies:$scope.notifyPolicies})),$el.on("change","input[type=radio]",function(event){var onError,onSuccess,policy,policyIndex,prev_level,target;return target=angular.element(event.currentTarget),policyIndex=target.parents(".policy-table-row").data("index"),policy=$scope.notifyPolicies[policyIndex],prev_level=policy.notify_level,policy.notify_level=parseInt(target.val(),10),onSuccess=function(){return $confirm.notify("success")},onError=function(){return $confirm.notify("error"),target.parents(".policy-table-row").find("input[value="+prev_level+"]").prop("checked",!0)},$repo.save(policy).then(onSuccess,onError)})},$scope.$on("$destroy",function(){return $el.off()}),bindOnce($scope,$attrs.ngModel,render)},{link:link}},module.directive("tgUserNotificationsList",["$tgRepo","$tgConfirm",UserNotificationsListDirective])}.call(this),function(){var AUTH_URL,GithubLoginButtonDirective,module,taiga;taiga=this.taiga,module=angular.module("taigaIntegrations"),AUTH_URL="https://github.com/login/oauth/authorize",GithubLoginButtonDirective=function($window,$params,$location,$config,$events,$confirm,$auth,$navUrls,$loader){var link,template;return template='\n \n Login with Github\n',link=function($scope,$el){var clientId,loginOnError,loginOnSuccess,loginWithGitHubAccount,renderGitHubButton;return(clientId=$config.get("gitHubClientId",null))?(renderGitHubButton=function(){return clientId?$el.html(template):void 0},loginOnSuccess=function(){var nextUrl;return nextUrl=$params.next&&$params.next!==$navUrls.resolve("login")?$params.next:$navUrls.resolve("home"),$events.setupConnection(),$location.search("next",null),$location.search("token",null),$location.search("state",null),$location.search("code",null),$location.path(nextUrl)},loginOnError=function(response){return $location.search("state",null),$location.search("code",null),$loader.pageLoaded(),response.data.error_message?$confirm.notify("light-error",response.data.error_message):$confirm.notify("light-error","Our Oompa Loompas have not been able to get you credentials from GitHub.")},loginWithGitHubAccount=function(){var code,data,token,type;return type=$params.state,code=$params.code,token=$params.token,"github"===type&&code?($loader.start(),data={code:code,token:token},$auth.login(data,type).then(loginOnSuccess,loginOnError)):void 0},renderGitHubButton(),loginWithGitHubAccount(),$el.on("click",".button-github",function(){var redirectToUri,url;return redirectToUri=$location.absUrl(),url=""+AUTH_URL+"?client_id="+clientId+"&redirect_uri="+redirectToUri+"&state=github&scope=user:email",$window.location.href=url}),$scope.$on("$destroy",function(){return $el.off()})):void 0},{link:link,restrict:"EA",template:""}},module.directive("tgGithubLoginButton",["$window","$routeParams","$tgLocation","$tgConfig","$tgEvents","$tgConfirm","$tgAuth","$tgNavUrls","tgLoader",GithubLoginButtonDirective])}.call(this),function(){var configure,module,taiga;taiga=this.taiga,module=angular.module("taigaPlugins",["ngRoute"]),configure=function($routeProvider){return $routeProvider.when("/humans.html",{templateUrl:"/plugins/humanshtml/templates/humans.html"})},module.config(["$routeProvider",configure])}.call(this),function(){var TermsNoticeDirective,module,taiga,template;taiga=this.taiga,module=angular.module("taigaPlugins",["ngRoute"]),template=_.template('

    \n By clicking "Sign up", you agree to our
    \n terms of service\n and\n privacy policy.\n

    '),TermsNoticeDirective=function($config){var privacyPolicyUrl,templateFn,termsOfServiceUrl;return privacyPolicyUrl=$config.get("privacyPolicyUrl"),termsOfServiceUrl=$config.get("termsOfServiceUrl"),templateFn=function(){var ctx;return privacyPolicyUrl&&termsOfServiceUrl?(ctx={termsUrl:termsOfServiceUrl,privacyUrl:privacyPolicyUrl},template(ctx)):""},{scope:{},restrict:"AE",template:templateFn}},module.directive("tgTermsNotice",["$tgConfig",TermsNoticeDirective])}.call(this),function(){var module;module=angular.module("taigaPlugins",["ngRoute"])}.call(this),angular.module("taigaBase").value("localesEn",{checksley:{defaultMessage:"This value seems to be invalid.","type-email":"This value should be a valid email.","type-url":"This value should be a valid url.","type-urlstrict":"This value should be a valid url.","type-number":"This value should be a valid number.","type-digits":"This value should be digits.","type-dateIso":"This value should be a valid date (YYYY-MM-DD).","type-alphanum":"This value should be alphanumeric.","type-phone":"This value should be a valid phone number.",notnull:"This value should not be null.",notblank:"This value should not be blank.",required:"This value is required.",regexp:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or less.",rangelength:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or less.",rangecheck:"You must select between %s and %s choices.",equalto:"This value should be the same."},common:{subject:"Subject",save:"Save",blocked:"Blocked",cancel:"Cancel",status:"Status","new-bulk":"New bulk insert","one-item-line":"One item per line..."},pagination:{next:"Next",prev:"Previous"},"markdown-editor":{"heading-1":"First Level Heading","heading-2":"Second Level Heading","heading-3":"Third Level Heading",bold:"Bold",italic:"Italic",strike:"Strike","bulleted-list":"Bulleted List","numeric-list":"Numeric List",picture:"Picture",link:"Link",quotes:"Quotes","code-block":"Code Block / Code",preview:"Preview",help:"Help",placeholder:"Your title here...","link-placeholder":"Your text to link here..."},us:{"title-new":"New User Story","team-requirement":"Team Requirement","client-requirement":"Client Requirement"}}); +(function(){var configure,init,module,modules,taiga;this.taiga=taiga={},this.taigaContribPlugins=this.taigaContribPlugins||[],taiga.generateHash=function(components){return null==components&&(components=[]),components=_.map(components,function(x){return JSON.stringify(x)}),hex_sha1(components.join(":"))},taiga.generateUniqueSessionIdentifier=function(){var date,randomNumber;return date=(new Date).getTime(),randomNumber=Math.floor(150994944*Math.random()),taiga.generateHash([date,randomNumber])},taiga.sessionId=taiga.generateUniqueSessionIdentifier(),configure=function($routeProvider,$locationProvider,$httpProvider,$provide,$tgEventsProvider,tgLoaderProvider){var authHttpIntercept,defaultHeaders,versionCheckHttpIntercept;return $routeProvider.when("/",{templateUrl:"project/projects.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/",{templateUrl:"project/project.html"}),$routeProvider.when("/project/:pslug/backlog",{templateUrl:"backlog/backlog.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/taskboard/:sslug",{templateUrl:"taskboard/taskboard.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/search",{templateUrl:"search/search.html",reloadOnSearch:!1}),$routeProvider.when("/project/:pslug/kanban",{templateUrl:"kanban/kanban.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/us/:usref",{templateUrl:"us/us-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/task/:taskref",{templateUrl:"task/task-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/wiki",{redirectTo:function(params){return"/project/"+params.pslug+"/wiki/home"}}),$routeProvider.when("/project/:pslug/wiki/:slug",{templateUrl:"wiki/wiki.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/team",{templateUrl:"team/team.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/issues",{templateUrl:"issue/issues.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/issue/:issueref",{templateUrl:"issue/issues-detail.html",resolve:{loader:tgLoaderProvider.add()}}),$routeProvider.when("/project/:pslug/admin/project-profile/details",{templateUrl:"admin/admin-project-profile.html"}),$routeProvider.when("/project/:pslug/admin/project-profile/default-values",{templateUrl:"admin/admin-project-default-values.html"}),$routeProvider.when("/project/:pslug/admin/project-profile/modules",{templateUrl:"admin/admin-project-modules.html"}),$routeProvider.when("/project/:pslug/admin/project-profile/export",{templateUrl:"admin/admin-project-export.html"}),$routeProvider.when("/project/:pslug/admin/project-values/us-status",{templateUrl:"admin/admin-project-values-us-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/us-points",{templateUrl:"admin/admin-project-values-us-points.html"}),$routeProvider.when("/project/:pslug/admin/project-values/task-status",{templateUrl:"admin/admin-project-values-task-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-status",{templateUrl:"admin/admin-project-values-issue-status.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-types",{templateUrl:"admin/admin-project-values-issue-types.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-priorities",{templateUrl:"admin/admin-project-values-issue-priorities.html"}),$routeProvider.when("/project/:pslug/admin/project-values/issue-severities",{templateUrl:"admin/admin-project-values-issue-severities.html"}),$routeProvider.when("/project/:pslug/admin/memberships",{templateUrl:"admin/admin-memberships.html"}),$routeProvider.when("/project/:pslug/admin/roles",{templateUrl:"admin/admin-roles.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/webhooks",{templateUrl:"admin/admin-third-parties-webhooks.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/github",{templateUrl:"admin/admin-third-parties-github.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/gitlab",{templateUrl:"admin/admin-third-parties-gitlab.html"}),$routeProvider.when("/project/:pslug/admin/third-parties/bitbucket",{templateUrl:"admin/admin-third-parties-bitbucket.html"}),$routeProvider.when("/project/:pslug/admin/contrib/:plugin",{templateUrl:"contrib/main.html"}),$routeProvider.when("/project/:pslug/user-settings/user-profile",{templateUrl:"user/user-profile.html"}),$routeProvider.when("/project/:pslug/user-settings/user-change-password",{templateUrl:"user/user-change-password.html"}),$routeProvider.when("/project/:pslug/user-settings/user-avatar",{templateUrl:"user/user-avatar.html"}),$routeProvider.when("/project/:pslug/user-settings/mail-notifications",{templateUrl:"user/mail-notifications.html"}),$routeProvider.when("/change-email/:email_token",{templateUrl:"user/change-email.html"}),$routeProvider.when("/cancel-account/:cancel_token",{templateUrl:"user/cancel-account.html"}),$routeProvider.when("/login",{templateUrl:"auth/login.html"}),$routeProvider.when("/register",{templateUrl:"auth/register.html"}),$routeProvider.when("/forgot-password",{templateUrl:"auth/forgot-password.html"}),$routeProvider.when("/change-password",{templateUrl:"auth/change-password-from-recovery.html"}),$routeProvider.when("/change-password/:token",{templateUrl:"auth/change-password-from-recovery.html"}),$routeProvider.when("/invitation/:token",{templateUrl:"auth/invitation.html"}),$routeProvider.when("/error",{templateUrl:"error/error.html"}),$routeProvider.when("/not-found",{templateUrl:"error/not-found.html"}),$routeProvider.when("/permission-denied",{templateUrl:"error/permission-denied.html"}),$routeProvider.otherwise({redirectTo:"/not-found"}),$locationProvider.html5Mode({enabled:!0,requireBase:!1}),defaultHeaders={"Content-Type":"application/json","Accept-Language":"en","X-Session-Id":taiga.sessionId},$httpProvider.defaults.headers["delete"]=defaultHeaders,$httpProvider.defaults.headers.patch=defaultHeaders,$httpProvider.defaults.headers.post=defaultHeaders,$httpProvider.defaults.headers.put=defaultHeaders,$httpProvider.defaults.headers.get={"X-Session-Id":taiga.sessionId},$tgEventsProvider.setSessionId(taiga.sessionId),authHttpIntercept=function($q,$location,$navUrls,$lightboxService){var httpResponseError;return httpResponseError=function(response){var nextPath;return 0===response.status?($lightboxService.closeAll(),$location.path($navUrls.resolve("error")),$location.replace()):401===response.status&&(nextPath=$location.path(),$location.url($navUrls.resolve("login")).search("next="+nextPath)),$q.reject(response)},{responseError:httpResponseError}},$provide.factory("authHttpIntercept",["$q","$location","$tgNavUrls","lightboxService",authHttpIntercept]),$httpProvider.interceptors.push("authHttpIntercept"),versionCheckHttpIntercept=function($q,$confirm){var httpResponseError,versionErrorMsg;return versionErrorMsg="Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost).",httpResponseError=function(response){return 400===response.status&&response.data.version?($confirm.notify("error",versionErrorMsg,null,1e4),$q.reject(response)):$q.reject(response)},{responseError:httpResponseError}},$provide.factory("versionCheckHttpIntercept",["$q","$tgConfirm",versionCheckHttpIntercept]),$httpProvider.interceptors.push("versionCheckHttpIntercept"),window.checksley.updateValidators({linewidth:function(val,width){var lines,valid;return lines=taiga.nl2br(val).split("
    "),valid=_.every(lines,function(line){return line.lengthi;i++)if(i in this&&this[i]===item)return i;return-1},__slice=[].slice,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};nl2br=function(){return function(str){var breakTag;return breakTag="
    ",(str+"").replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g,"$1"+breakTag+"$2")}}(this),bindMethods=function(){return function(object){var dependencies,methods;return dependencies=_.keys(object),methods=[],_.forIn(object,function(value,key){return __indexOf.call(dependencies,key)<0?methods.push(key):void 0}),_.bindAll(object,methods)}}(this),bindOnce=function(){return function(scope,attr,continuation){var delBind,val;return val=scope.$eval(attr),void 0!==val?continuation(val):(delBind=null,delBind=scope.$watch(attr,function(val){return void 0!==val?(continuation(val),delBind?delBind():void 0):void 0}))}}(this),mixOf=function(){var Mixed,base,method,mixin,mixins,name,_i,_ref;for(base=arguments[0],mixins=2<=arguments.length?__slice.call(arguments,1):[],Mixed=function(_super){function Mixed(){return Mixed.__super__.constructor.apply(this,arguments)}return __extends(Mixed,_super),Mixed}(base),_i=mixins.length-1;_i>=0;_i+=-1){mixin=mixins[_i],_ref=mixin.prototype;for(name in _ref)method=_ref[name],Mixed.prototype[name]=method}return Mixed},trim=function(data,char){return _.str.trim(data,char)},slugify=function(data){return _.str.slugify(data)},unslugify=function(data){return data?_.str.capitalize(data.replace(/-/g," ")):data},toggleText=function(element,texts){var nextTextPosition,text;return nextTextPosition=element.data("nextTextPosition"),(null==nextTextPosition||nextTextPosition>=texts.length)&&(nextTextPosition=0),text=texts[nextTextPosition],element.data("nextTextPosition",nextTextPosition+1),element.text(text)},groupBy=function(coll,pred){var item,result,_i,_len;for(result={},_i=0,_len=coll.length;_len>_i;_i++)item=coll[_i],result[pred(item)]=item;return result},timeout=function(wait,continuation){return window.setTimeout(continuation,wait)},cancelTimeout=function(timeoutVar){return window.clearTimeout(timeoutVar)},scopeDefer=function(scope,func){return _.defer(function(){return function(){return scope.$apply(func)}}(this))},toString=function(value){return _.isNumber(value)?value+"":_.isString(value)?value:_.isPlainObject(value)?JSON.stringify(value):_.isUndefined(value)?"":value.toString()},joinStr=function(str,coll){return _.str.join(str,coll)},debounce=function(wait,func){return _.debounce(func,wait,{leading:!0,trailing:!1})},debounceLeading=function(wait,func){return _.debounce(func,wait,{leading:!1,trailing:!0})},startswith=function(str1,str2){return _.str.startsWith(str1,str2)},sizeFormat=function(input,precision){var number,size,units;return null==precision&&(precision=1),isNaN(parseFloat(input))||!isFinite(input)?"-":0===input?"0 bytes":(units=["bytes","KB","MB","GB","TB","PB"],number=Math.floor(Math.log(input)/Math.log(1024)),number>5&&(number=5),size=(input/Math.pow(1024,number)).toFixed(precision),""+size+" "+units[number])},taiga=this.taiga,taiga.nl2br=nl2br,taiga.bindMethods=bindMethods,taiga.bindOnce=bindOnce,taiga.mixOf=mixOf,taiga.trim=trim,taiga.slugify=slugify,taiga.unslugify=unslugify,taiga.toggleText=toggleText,taiga.groupBy=groupBy,taiga.timeout=timeout,taiga.cancelTimeout=cancelTimeout,taiga.scopeDefer=scopeDefer,taiga.toString=toString,taiga.joinStr=joinStr,taiga.debounce=debounce,taiga.debounceLeading=debounceLeading,taiga.startswith=startswith,taiga.sizeFormat=sizeFormat}.call(this),function(){var FiltersMixin,PageMixin,groupBy,joinStr,taiga,toString,trim;taiga=this.taiga,groupBy=this.taiga.groupBy,joinStr=this.taiga.joinStr,trim=this.taiga.trim,toString=this.taiga.toString,PageMixin=function(){function PageMixin(){}return PageMixin.prototype.fillUsersAndRoles=function(users,roles){var activeUsers,availableRoles;return activeUsers=_.filter(users,function(){return function(user){return user.is_active}}(this)),this.scope.activeUsers=_.sortBy(activeUsers,"full_name_display"),this.scope.activeUsersById=groupBy(this.scope.activeUsers,function(e){return e.id}),this.scope.users=_.sortBy(users,"full_name_display"),this.scope.usersById=groupBy(this.scope.users,function(e){return e.id}),this.scope.roles=_.sortBy(roles,"order"),availableRoles=_(this.scope.project.memberships).map("role").uniq().value(),this.scope.computableRoles=_(roles).filter("computable").filter(function(x){return _.contains(availableRoles,x.id)}).value()},PageMixin.prototype.loadUsersAndRoles=function(){var promise;return promise=this.q.all([this.rs.projects.usersList(this.scope.projectId),this.rs.projects.rolesList(this.scope.projectId)]),promise.then(function(_this){return function(results){var roles,users;return users=results[0],roles=results[1],_this.fillUsersAndRoles(users,roles),results}}(this))},PageMixin}(),taiga.PageMixin=PageMixin,FiltersMixin=function(){function FiltersMixin(){}return FiltersMixin.prototype.selectFilter=function(name,value,load){var existing,location,params;return null==load&&(load=!1),params=this.location.search(),void 0!==params[name]&&"page"!==name&&(existing=_.map(taiga.toString(params[name]).split(","),function(x){return trim(x)}),existing.push(taiga.toString(value)),existing=_.compact(existing),value=joinStr(",",_.uniq(existing))),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)},FiltersMixin.prototype.replaceFilter=function(name,value,load){var location;return null==load&&(load=!1),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)},FiltersMixin.prototype.replaceAllFilters=function(filters,load){var location;return null==load&&(load=!1),location=load?this.location:this.location.noreload(this.scope),location.search(filters)},FiltersMixin.prototype.unselectFilter=function(name,value,load){var location,newValues,params,parsedValues;return null==load&&(load=!1),params=this.location.search(),void 0!==params[name]?((void 0===value||null===value)&&delete params[name],parsedValues=_.map(taiga.toString(params[name]).split(","),function(x){return trim(x)}),newValues=_.reject(parsedValues,function(x){return x===taiga.toString(value)}),newValues=_.compact(newValues),value=_.isEmpty(newValues)?null:joinStr(",",_.uniq(newValues)),location=load?this.location:this.location.noreload(this.scope),location.search(name,value)):void 0},FiltersMixin}(),taiga.FiltersMixin=FiltersMixin}.call(this),function(){var module;module=angular.module("taigaAdmin",[])}.call(this),function(){var AuthService,CancelAccountDirective,ChangeEmailDirective,ChangePasswordFromRecoveryDirective,ForgotPasswordDirective,InvitationDirective,LoginDirective,PublicRegisterMessageDirective,RegisterDirective,debounce,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,debounce=this.taiga.debounce,module=angular.module("taigaAuth",["taigaResources"]),AuthService=function(_super){function AuthService(rootscope,storage,model,rs,http,urls){this.rootscope=rootscope,this.storage=storage,this.model=model,this.rs=rs,this.http=http,this.urls=urls,AuthService.__super__.constructor.call(this)}return __extends(AuthService,_super),AuthService.$inject=["$rootScope","$tgStorage","$tgModel","$tgResources","$tgHttp","$tgUrls"],AuthService.prototype.getUser=function(){var user,userData;return this.rootscope.user?this.rootscope.user:(userData=this.storage.get("userInfo"),userData?(user=this.model.make_model("users",userData),this.rootscope.user=user,user):null)},AuthService.prototype.setUser=function(user){return this.rootscope.auth=user,this.rootscope.$broadcast("i18n:change",user.default_language),this.storage.set("userInfo",user.getAttrs()),this.rootscope.user=user},AuthService.prototype.clear=function(){return this.rootscope.auth=null,this.rootscope.user=null,this.storage.remove("userInfo")},AuthService.prototype.setToken=function(token){return this.storage.set("token",token)},AuthService.prototype.getToken=function(){return this.storage.get("token")},AuthService.prototype.removeToken=function(){return this.storage.remove("token")},AuthService.prototype.isAuthenticated=function(){return null!==this.getUser()?!0:!1},AuthService.prototype.login=function(data,type){var url;return url=this.urls.resolve("auth"),data=_.clone(data,!1),data.type=type?type:"normal",this.removeToken(),this.http.post(url,data).then(function(_this){return function(data){var user;return user=_this.model.make_model("users",data.data),_this.setToken(user.auth_token),_this.setUser(user),user}}(this))},AuthService.prototype.logout=function(){return this.removeToken(),this.clear()},AuthService.prototype.register=function(data,type,existing){var url;return url=this.urls.resolve("auth-register"),data=_.clone(data,!1),data.type=type?type:"public","private"===type&&(data.existing=existing?existing:!1),this.removeToken(),this.http.post(url,data).then(function(_this){return function(response){var user;return user=_this.model.make_model("users",response.data),_this.setToken(user.auth_token),_this.setUser(user),user}}(this))},AuthService.prototype.getInvitation=function(token){return this.rs.invitations.get(token)},AuthService.prototype.acceptInvitiationWithNewUser=function(data){return this.register(data,"private",!1)},AuthService.prototype.acceptInvitiationWithExistingUser=function(data){return this.register(data,"private",!0)},AuthService.prototype.forgotPassword=function(data){var url;return url=this.urls.resolve("users-password-recovery"),data=_.clone(data,!1),this.removeToken(),this.http.post(url,data)},AuthService.prototype.changePasswordFromRecovery=function(data){var url;return url=this.urls.resolve("users-change-password-from-recovery"),data=_.clone(data,!1),this.removeToken(),this.http.post(url,data)},AuthService.prototype.changeEmail=function(data){var url;return url=this.urls.resolve("users-change-email"),data=_.clone(data,!1),this.http.post(url,data)},AuthService.prototype.cancelAccount=function(data){var url;return url=this.urls.resolve("users-cancel-account"),data=_.clone(data,!1),this.http.post(url,data)},AuthService}(taiga.Service),module.service("$tgAuth",AuthService),PublicRegisterMessageDirective=function($config,$navUrls,templates){var template,templateFn;return template=templates.get("auth/login-text.html",!0),templateFn=function(){var publicRegisterEnabled;return publicRegisterEnabled=$config.get("publicRegisterEnabled"),publicRegisterEnabled?template({url:$navUrls.resolve("register")}):""},{restrict:"AE",scope:{},template:templateFn}},module.directive("tgPublicRegisterMessage",["$tgConfig","$tgNavUrls","$tgTemplate",PublicRegisterMessageDirective]),LoginDirective=function($auth,$confirm,$location,$config,$routeParams,$navUrls,$events){var link;return link=function($scope,$el){var onError,onSuccess,submit;return onSuccess=function(){var nextUrl;return nextUrl=$routeParams.next&&$routeParams.next!==$navUrls.resolve("login")?$routeParams.next:$navUrls.resolve("home"),$events.setupConnection(),$location.path(nextUrl)},onError=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your username/email or password are incorrect.")},submit=debounce(2e3,function(){return function(event){var data,form,promise;return event.preventDefault(),form=new checksley.Form($el.find("form.login-form")),form.validate()?(data={username:$el.find("form.login-form input[name=username]").val(),password:$el.find("form.login-form input[name=password]").val()},promise=$auth.login(data),promise.then(onSuccess,onError)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLogin",["$tgAuth","$tgConfirm","$tgLocation","$tgConfig","$routeParams","$tgNavUrls","$tgEvents",LoginDirective]),RegisterDirective=function($auth,$confirm,$location,$navUrls,$config,$analytics){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $config.get("publicRegisterEnabled")||($location.path($navUrls.resolve("not-found")),$location.replace()),$scope.data={},form=$el.find("form").checksley({onlyOneErrorElement:!0}),onSuccessSubmit=function(){return $analytics.trackEvent("auth","register","user registration",1),$confirm.notify("success","Our Oompa Loompas are happy, welcome to Taiga."),$location.path($navUrls.resolve("home"))},onErrorSubmit=function(response){return null!=response.data._error_message&&$confirm.notify("light-error","According to our Oompa Loompas there was an error. "+response.data._error_message),form.setErrors(response.data)},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.register($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgRegister",["$tgAuth","$tgConfirm","$tgLocation","$tgNavUrls","$tgConfig","$tgAnalytics",RegisterDirective]),ForgotPasswordDirective=function($auth,$confirm,$location,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},form=$el.find("form").checksley(),onSuccessSubmit=function(response){return $location.path($navUrls.resolve("login")),$confirm.success("Check your inbox!
    We have sent a mail to
    "+response.data.email+"
    with the instructions to set a new password")},onErrorSubmit=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your are not registered yet.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.forgotPassword($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgForgotPassword",["$tgAuth","$tgConfirm","$tgLocation","$tgNavUrls",ForgotPasswordDirective]),ChangePasswordFromRecoveryDirective=function($auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},null!=$params.token?($scope.tokenInParams=!0,$scope.data.token=$params.token):$scope.tokenInParams=!1,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $location.path($navUrls.resolve("login")),$confirm.success("Our Oompa Loompas saved your new password.
    Try to sign in with it.")},onErrorSubmit=function(response){return $confirm.notify("light-error","One of our Oompa Loompas say '"+response.data._error_message+"'.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.changePasswordFromRecovery($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgChangePasswordFromRecovery",["$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",ChangePasswordFromRecoveryDirective]),InvitationDirective=function($auth,$confirm,$location,$params,$navUrls,$analytics){var link;return link=function($scope,$el){var loginForm,onErrorSubmitLogin,onErrorSubmitRegister,onSuccessSubmitLogin,onSuccessSubmitRegister,promise,registerForm,submitLogin,submitRegister,token;return token=$params.token,promise=$auth.getInvitation(token),promise.then(function(invitation){return $scope.invitation=invitation}),promise.then(null,function(){return $location.path($navUrls.resolve("login")),$confirm.success("Ooops, we have a problem
    Our Oompa Loompas can't find your invitation.")}),$scope.dataLogin={token:token},loginForm=$el.find("form.login-form").checksley({onlyOneErrorElement:!0}),onSuccessSubmitLogin=function(){return $analytics.trackEvent("auth","invitationAccept","invitation accept with existing user",1),$location.path($navUrls.resolve("project",{project:$scope.invitation.project_slug})),$confirm.notify("success","You've successfully joined this project","Welcome to "+_.escape($scope.invitation.project_name))},onErrorSubmitLogin=function(){return $confirm.notify("light-error","According to our Oompa Loompas, your are not registered yet or typed an invalid password.")},submitLogin=debounce(2e3,function(){return function(event){return event.preventDefault(),loginForm.validate()?(promise=$auth.acceptInvitiationWithExistingUser($scope.dataLogin),promise.then(onSuccessSubmitLogin,onErrorSubmitLogin)):void 0}}(this)),$el.on("submit","form.login-form",submitLogin),$el.on("click",".button-login",submitLogin),$scope.dataRegister={token:token},registerForm=$el.find("form.register-form").checksley(),onSuccessSubmitRegister=function(){return $analytics.trackEvent("auth","invitationAccept","invitation accept with new user",1),$location.path($navUrls.resolve("project",{project:$scope.invitation.project_slug})),$confirm.notify("success","You've successfully joined this project","Welcome to "+_.escape($scope.invitation.project_name))},onErrorSubmitRegister=function(){return $confirm.notify("light-error","According to our Oompa Loompas, that username or email is already in use.")},submitRegister=debounce(2e3,function(){return function(event){return event.preventDefault(),registerForm.validate()?(promise=$auth.acceptInvitiationWithNewUser($scope.dataRegister),promise.then(onSuccessSubmitRegister,onErrorSubmitRegister)):void 0}}(this)),$el.on("submit","form.register-form",submitRegister),$el.on("click",".button-register",submitRegister)},{link:link}},module.directive("tgInvitation",["$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls","$tgAnalytics",InvitationDirective]),ChangeEmailDirective=function($repo,$model,$auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},$scope.data.email_token=$params.email_token,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $repo.queryOne("users",$auth.getUser().id).then(function(){return function(data){return $auth.setUser(data),$location.path($navUrls.resolve("home")),$confirm.success("Our Oompa Loompas updated your email")}}(this))},onErrorSubmit=function(response){return $confirm.notify("error","One of our Oompa Loompas says '"+response.data._error_message+"'.")},submit=function(){var promise;if(form.validate())return promise=$auth.changeEmail($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)},$el.on("submit",function(event){return event.preventDefault(),submit()}),$el.on("click","a.button-change-email",function(event){return event.preventDefault(),submit()})},{link:link}},module.directive("tgChangeEmail",["$tgRepo","$tgModel","$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",ChangeEmailDirective]),CancelAccountDirective=function($repo,$model,$auth,$confirm,$location,$params,$navUrls){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit;return $scope.data={},$scope.data.cancel_token=$params.cancel_token,form=$el.find("form").checksley(),onSuccessSubmit=function(){return $auth.logout(),$location.path($navUrls.resolve("home")),$confirm.success("Our Oompa Loompas removed your account")},onErrorSubmit=function(response){return $confirm.notify("error","One of our Oompa Loompas says '"+response.data._error_message+"'.")},submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?(promise=$auth.cancelAccount($scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgCancelAccount",["$tgRepo","$tgModel","$tgAuth","$tgConfirm","$tgLocation","$routeParams","$tgNavUrls",CancelAccountDirective])}.call(this),function(){var module;module=angular.module("taigaBacklog",[])}.call(this),function(){var TaigaMainDirective,bindOnce,groupBy,init,module,taiga,urls;taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaBase",["taigaLocales"]),TaigaMainDirective=function($rootscope,$window){var link;return link=function(){return $window.onresize=function(){return $rootscope.$broadcast("resize")}},{link:link}},module.directive("tgMain",["$rootScope","$window",TaigaMainDirective]),urls={home:"/",error:"/error","not-found":"/not-found","permission-denied":"/permission-denied",login:"/login","forgot-password":"/forgot-password","change-password":"/change-password/:token","change-email":"/change-email/:token","cancel-account":"/cancel-account/:token",register:"/register",invitation:"/invitation/:token","create-project":"/create-project",profile:"/:user",project:"/project/:project","project-backlog":"/project/:project/backlog","project-taskboard":"/project/:project/taskboard/:sprint","project-kanban":"/project/:project/kanban","project-issues":"/project/:project/issues","project-search":"/project/:project/search","project-userstories-detail":"/project/:project/us/:ref","project-tasks-detail":"/project/:project/task/:ref","project-issues-detail":"/project/:project/issue/:ref","project-wiki":"/project/:project/wiki","project-wiki-page":"/project/:project/wiki/:slug","project-team":"/project/:project/team","project-admin-home":"/project/:project/admin/project-profile/details","project-admin-project-profile-details":"/project/:project/admin/project-profile/details","project-admin-project-profile-default-values":"/project/:project/admin/project-profile/default-values","project-admin-project-profile-modules":"/project/:project/admin/project-profile/modules","project-admin-project-profile-export":"/project/:project/admin/project-profile/export","project-admin-project-values-us-status":"/project/:project/admin/project-values/us-status","project-admin-project-values-us-points":"/project/:project/admin/project-values/us-points","project-admin-project-values-task-status":"/project/:project/admin/project-values/task-status","project-admin-project-values-issue-status":"/project/:project/admin/project-values/issue-status","project-admin-project-values-issue-types":"/project/:project/admin/project-values/issue-types","project-admin-project-values-issue-priorities":"/project/:project/admin/project-values/issue-priorities","project-admin-project-values-issue-severities":"/project/:project/admin/project-values/issue-severities","project-admin-memberships":"/project/:project/admin/memberships","project-admin-roles":"/project/:project/admin/roles","project-admin-third-parties-webhooks":"/project/:project/admin/third-parties/webhooks","project-admin-third-parties-github":"/project/:project/admin/third-parties/github","project-admin-third-parties-gitlab":"/project/:project/admin/third-parties/gitlab","project-admin-third-parties-bitbucket":"/project/:project/admin/third-parties/bitbucket","project-admin-contrib":"/project/:project/admin/contrib/:plugin","user-settings-user-profile":"/project/:project/user-settings/user-profile","user-settings-user-change-password":"/project/:project/user-settings/user-change-password","user-settings-user-avatar":"/project/:project/user-settings/user-avatar","user-settings-mail-notifications":"/project/:project/user-settings/mail-notifications"},init=function($log,$navurls){return $log.debug("Initialize navigation urls"),$navurls.update(urls) +},module.run(["$log","$tgNavUrls",init])}.call(this),function(){var AnimationFrame,AppTitle,CheckPermissionDirective,LimitLineLengthDirective,ProjectUrl,Qqueue,SelectedText,Template,ToggleCommentDirective,module,taiga,__slice=[].slice;taiga=this.taiga,module=angular.module("taigaCommon",[]),SelectedText=function($window,$document){var get;return get=function(){return $window.getSelection?$window.getSelection().toString():$document.selection?$document.selection.createRange().text:""},{get:get}},module.factory("$selectedText",["$window","$document",SelectedText]),CheckPermissionDirective=function(){var link,render;return render=function($el,project,permission){return project.my_permissions.indexOf(permission)>-1?$el.removeClass("hidden"):void 0},link=function($scope,$el,$attrs){var permission;return $el.addClass("hidden"),permission=$attrs.tgCheckPermission,$scope.$watch("project",function(project){return null!=project?render($el,project,permission):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgCheckPermission",CheckPermissionDirective),AnimationFrame=function(){var add,animationFrame,performAnimation,tail;return animationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame,performAnimation=function(){return function(){var fn;return fn=tail.shift(),fn(),tail.length?animationFrame(performAnimation):void 0}}(this),tail=[],add=function(){var fn,_i,_len,_results;for(_results=[],_i=0,_len=arguments.length;_len>_i;_i++)fn=arguments[_i],tail.push(fn),_results.push(1===tail.length?animationFrame(performAnimation):void 0);return _results},{add:add}},module.factory("animationFrame",AnimationFrame),ToggleCommentDirective=function(){var link;return link=function($scope,$el){return $el.find("textarea").on("focus",function(){return $el.addClass("active")})},{link:link}},module.directive("tgToggleComment",ToggleCommentDirective),AppTitle=function(){var set;return set=function(text){return $("title").text(text)},{set:set}},module.factory("$appTitle",AppTitle),ProjectUrl=function($navurls){var get;return get=function(project){var ctx;return ctx={project:project.slug},project.is_backlog_activated&&project.my_permissions.indexOf("view_us")>-1?$navurls.resolve("project-backlog",ctx):project.is_kanban_activated&&project.my_permissions.indexOf("view_us")>-1?$navurls.resolve("project-kanban",ctx):project.is_wiki_activated&&project.my_permissions.indexOf("view_wiki_pages")>-1?$navurls.resolve("project-wiki",ctx):project.is_issues_activated&&project.my_permissions.indexOf("view_issues")>-1?$navurls.resolve("project-issues",ctx):$navurls.resolve("project",ctx)},{get:get}},module.factory("$projectUrl",["$tgNavUrls",ProjectUrl]),LimitLineLengthDirective=function(){var link;return link=function($scope,$el){var maxColsPerLine;return maxColsPerLine=parseInt($el.attr("cols")),$el.on("keyup",function(event){var code,lines;return code=event.keyCode,lines=$el.val().split("\n"),_.each(lines,function(line,index){return lines[index]=line.substring(0,maxColsPerLine-2)}),$el.val(lines.join("\n"))})},{link:link}},module.directive("tgLimitLineLength",LimitLineLengthDirective),Qqueue=function($q){var deferred,lastPromise,qqueue;return deferred=$q.defer(),deferred.resolve(),lastPromise=deferred.promise,qqueue={bindAdd:function(_this){return function(fn){return function(){var args;return args=1<=arguments.length?__slice.call(arguments,0):[],lastPromise=lastPromise.then(function(){return fn.apply(_this,args)})}}}(this),add:function(){return function(fn){return lastPromise=lastPromise?lastPromise.then(fn):fn(),qqueue}}(this)}},module.factory("$tgQqueue",["$q",Qqueue]),Template=function($templateCache){return{get:function(){return function(name,lodash){var tmp;return null==lodash&&(lodash=!1),tmp=$templateCache.get(name),lodash&&(tmp=_.template(tmp)),tmp}}(this)}},module.factory("$tgTemplate",["$templateCache",Template])}.call(this),function(){var EventsProvider,EventsService,bindMethods,module,startswith,taiga;taiga=this.taiga,startswith=this.taiga.startswith,bindMethods=this.taiga.bindMethods,module=angular.module("taigaEvents",[]),EventsService=function(){function EventsService(win,log,config,auth){this.win=win,this.log=log,this.config=config,this.auth=auth,bindMethods(this)}return EventsService.prototype.initialize=function(sessionId){return this.sessionId=sessionId,this.subscriptions={},this.connected=!1,this.error=!1,this.pendingMessages=[],void 0===this.win.WebSocket?this.log.info("WebSockets not supported on your browser"):void 0},EventsService.prototype.setupConnection=function(){var loc,path,scheme,url;return this.stopExistingConnection(),(url=this.config.get("eventsUrl"))?(startswith(url,"ws:")||startswith(url,"wss:")||(loc=this.win.location,scheme="https:"===loc.protocol?"wss:":"ws:",path=_.str.ltrim(url,"/"),url=""+scheme+"//"+loc.host+"/"+path),this.ws=new this.win.WebSocket(url),this.ws.addEventListener("open",this.onOpen),this.ws.addEventListener("message",this.onMessage),this.ws.addEventListener("error",this.onError),this.ws.addEventListener("close",this.onClose)):void 0},EventsService.prototype.stopExistingConnection=function(){return void 0!==this.ws?(this.ws.removeEventListener("open",this.onOpen),this.ws.removeEventListener("close",this.onClose),this.ws.removeEventListener("error",this.onError),this.ws.removeEventListener("message",this.onMessage),this.ws.close(),delete this.ws):void 0},EventsService.prototype.serialize=function(message){return _.isObject(message)?JSON.stringify(message):message},EventsService.prototype.sendMessage=function(message){var messages,msg,_i,_len,_results;if(this.pendingMessages.push(message),this.connected){for(messages=_.map(this.pendingMessages,this.serialize),this.pendingMessages=[],_results=[],_i=0,_len=messages.length;_len>_i;_i++)msg=messages[_i],_results.push(this.ws.send(msg));return _results}},EventsService.prototype.subscribe=function(scope,routingKey,callback){var message,subscription;if(!this.error)return this.log.debug("Subscribe to: "+routingKey),subscription={scope:scope,routingKey:routingKey,callback:_.debounce(callback,500,{leading:!0,trailing:!1})},message={cmd:"subscribe",routing_key:routingKey},this.subscriptions[routingKey]=subscription,this.sendMessage(message),scope.$on("$destroy",function(_this){return function(){return _this.unsubscribe(routingKey)}}(this))},EventsService.prototype.unsubscribe=function(routingKey){var message;if(!this.error)return this.log.debug("Unsubscribe from: "+routingKey),message={cmd:"unsubscribe",routing_key:routingKey},this.sendMessage(message)},EventsService.prototype.onOpen=function(){var message,token;return this.connected=!0,this.log.debug("WebSocket connection opened"),token=this.auth.getToken(),message={cmd:"auth",data:{token:token,sessionId:this.sessionId}},this.sendMessage(message)},EventsService.prototype.onMessage=function(event){var data,routingKey,subscription;return this.log.debug("WebSocket message received: "+event.data),data=JSON.parse(event.data),routingKey=data.routing_key,null!=this.subscriptions[routingKey]?(subscription=this.subscriptions[routingKey],subscription.scope.$apply(function(){return subscription.callback(data.data)})):void 0},EventsService.prototype.onError=function(error){return this.log.error("WebSocket error: "+error),this.error=!0},EventsService.prototype.onClose=function(){return this.log.debug("WebSocket closed."),this.connected=!1},EventsService}(),EventsProvider=function(){function EventsProvider(){}return EventsProvider.prototype.setSessionId=function(sessionId){return this.sessionId=sessionId},EventsProvider.prototype.$get=function($win,$log,$conf,$auth){var service;return service=new EventsService($win,$log,$conf,$auth),service.initialize(this.sessionId),service},EventsProvider.prototype.$get.$inject=["$window","$log","$tgConfig","$tgAuth"],EventsProvider}(),module.provider("$tgEvents",EventsProvider)}.call(this),function(){var FeedbackDirective,bindOnce,debounce,groupBy,mixOf,module,taiga,trim;taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,mixOf=this.taiga.mixOf,debounce=this.taiga.debounce,trim=this.taiga.trim,module=angular.module("taigaFeedback",[]),FeedbackDirective=function($lightboxService,$repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley(),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("feedback",$scope.feedback),promise.then(function(){return $loading.finish(submitButton),$lightboxService.close($el),$confirm.notify("success","\\o/ we'll be happy to read your")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("feedback:show",function(){return $scope.$apply(function(){return $scope.feedback={}}),$lightboxService.open($el),$el.find("textarea").focus()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbFeedback",["lightboxService","$tgRepo","$tgConfirm","$tgLoading",FeedbackDirective])}.call(this),function(){var module;module=angular.module("taigaIntegrations",[])}.call(this),function(){var module;module=angular.module("taigaIssues",[])}.call(this),function(){var module;module=angular.module("taigaKanban",[])}.call(this),function(){var module;module=angular.module("taigaLocales",[])}.call(this),function(){var ProjectMenuDirective,ProjectsNavigationController,ProjectsNavigationDirective,bindOnce,groupBy,module,taiga,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,module=angular.module("taigaNavMenu",[]),ProjectsNavigationController=function(_super){function ProjectsNavigationController(scope,rootscope,rs,navurls,projectUrl){var promise;this.scope=scope,this.rootscope=rootscope,this.rs=rs,this.navurls=navurls,this.projectUrl=projectUrl,promise=this.loadInitialData(),promise.then(null,function(){return console.log("FAIL")}),this.scope.$on("projects:reload",function(_this){return function(){return _this.loadInitialData()}}(this)),this.scope.$on("project:loaded",function(_this){return function(){return _this.loadInitialData()}}(this))}return __extends(ProjectsNavigationController,_super),ProjectsNavigationController.$inject=["$scope","$rootScope","$tgResources","$tgNavUrls","$projectUrl"],ProjectsNavigationController.prototype.loadInitialData=function(){return this.rs.projects.list().then(function(_this){return function(projects){var project,_i,_len;for(_i=0,_len=projects.length;_len>_i;_i++)project=projects[_i],project.url=_this.projectUrl.get(project);return _this.scope.projects=projects,_this.scope.filteredProjects=projects,_this.scope.filterText="",projects}}(this))},ProjectsNavigationController.prototype.newProject=function(){return this.scope.$apply(function(_this){return function(){return _this.rootscope.$broadcast("projects:create")}}(this))},ProjectsNavigationController.prototype.filterProjects=function(text){return this.scope.filteredProjects=_.filter(this.scope.projects,function(project){return project.name.toLowerCase().indexOf(text)>-1}),this.scope.filterText=text,this.rootscope.$broadcast("projects:filtered")},ProjectsNavigationController}(taiga.Controller),module.controller("ProjectsNavigationController",ProjectsNavigationController),ProjectsNavigationDirective=function($rootscope,animationFrame,$timeout,tgLoader,$location,$compile,$template){var baseTemplate,hideMenu,link,loadingStart,overlay,projectsTemplate;return baseTemplate=$template.get("project/project-navigation-base.html",!0),projectsTemplate=$template.get("project/project-navigation-list.html",!0),overlay=$(".projects-nav-overlay"),loadingStart=0,hideMenu=function(){var difftime,timeoutValue;return overlay.is(":visible")?(difftime=(new Date).getTime()-loadingStart,timeoutValue=0,1e3>difftime&&(timeoutValue=1e3-timeoutValue),timeout(timeoutValue,function(){return overlay.one("transitionend",function(){return $(document.body).removeClass("loading-project open-projects-nav closed-projects-nav").css("overflow-x","visible"),overlay.hide()}),$(document.body).addClass("closed-projects-nav"),tgLoader.disablePreventLoading()})):void 0},link=function($scope,$el,$attrs,$ctrls){var $ctrl,render,renderProjects;return $ctrl=$ctrls[0],$rootscope.$on("project:loaded",hideMenu),renderProjects=function(projects){var html;return html=projectsTemplate({projects:projects}),$el.find(".projects-list").html(html),$scope.$emit("regenerate:project-pagination")},render=function(projects){return $el.html($compile(baseTemplate())($scope)),renderProjects(projects)},overlay.on("click",function(){return hideMenu()}),$(document).on("keydown",function(){return function(e){var code;return code=e.keyCode?e.keyCode:e.which,27===code?hideMenu():void 0}}(this)),$scope.$on("nav:projects-list:open",function(){return $(document.body).hasClass("open-projects-nav")||animationFrame.add(function(){return function(){return overlay.show()}}(this)),animationFrame.add(function(){return function(){return $(document.body).css("overflow-x","hidden")}}(this),function(){return function(){return $(document.body).toggleClass("open-projects-nav")}}(this))}),$el.on("click",".projects-list > li > a",function(event){var currentUrl,nextUrl,target;return target=angular.element(event.currentTarget),nextUrl=target.prop("href"),currentUrl=$location.absUrl(),nextUrl===currentUrl?void hideMenu():($(document.body).addClass("loading-project"),tgLoader.preventLoading(),loadingStart=(new Date).getTime())}),$el.on("click",".create-project-button",function(event){return event.preventDefault(),$ctrl.newProject()}),$el.on("keyup",".search-project",function(event){var target;return target=angular.element(event.currentTarget),$ctrl.filterProjects(target.val())}),$scope.$on("projects:filtered",function(){return renderProjects($scope.filteredProjects)}),$scope.$watch("projects",function(projects){return null!=projects?render(projects):void 0})},{require:["tgProjectsNav"],controller:ProjectsNavigationController,link:link}},module.directive("tgProjectsNav",["$rootScope","animationFrame","$timeout","tgLoader","$tgLocation","$compile","$tgTemplate",ProjectsNavigationDirective]),ProjectMenuDirective=function($log,$compile,$auth,$rootscope,$tgAuth,$location,$navUrls,$config,$template){var getSectionName,link,mainTemplate,menuEntriesTemplate,renderMainMenu,renderMenuEntries,videoConferenceUrl;return menuEntriesTemplate=$template.get("project/project-menu.html",!0),mainTemplate=_.template('\n'),getSectionName=function($el,sectionName,project){var oldSectionName,_ref;return oldSectionName=null!=(_ref=$el.find("a.active").parent().attr("id"))?_ref.replace("nav-",""):void 0,"backlog-kanban"===sectionName&&("backlog"===oldSectionName||"kanban"===oldSectionName?sectionName=oldSectionName:project.is_backlog_activated&&!project.is_kanban_activated?sectionName="backlog":!project.is_backlog_activated&&project.is_kanban_activated&&(sectionName="kanban")),sectionName},renderMainMenu=function($el){var html;return html=mainTemplate({}),$el.html(html)},renderMenuEntries=function($el,targetScope,project){var container,ctx,dom,sectionName;return null==project&&(project={}),container=$el.find(".menu-container"),sectionName=getSectionName($el,targetScope.section,project),ctx={user:$auth.getUser(),project:project,feedbackEnabled:$config.get("feedbackEnabled")},dom=$compile(menuEntriesTemplate(ctx))(targetScope),dom.find("a.active").removeClass("active"),dom.find("#nav-"+sectionName+" > a").addClass("active"),container.replaceWith(dom)},videoConferenceUrl=function(project){var baseUrl,url;if("appear-in"===project.videoconferences)baseUrl="https://appear.in/";else{if("talky"!==project.videoconferences)return"";baseUrl="https://talky.io/"}return url=project.videoconferences_salt?""+project.slug+"-"+project.videoconferences_salt:""+project.slug,baseUrl+url},link=function($scope,$el){var project;return renderMainMenu($el),project=null,$el.on("click",".logo",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$rootscope.$broadcast("nav:projects-list:open")}),$el.on("click",".user-settings .avatar",function(event){return event.preventDefault(),$el.find(".user-settings .popover").popover().open()}),$el.on("click",".logout",function(event){return event.preventDefault(),$auth.logout(),$scope.$apply(function(){return $location.path($navUrls.resolve("login"))})}),$el.on("click","#nav-search > a",function(event){return event.preventDefault(),$rootscope.$broadcast("search-box:show",project)}),$el.on("click",".feedback",function(event){return event.preventDefault(),$rootscope.$broadcast("feedback:show")}),$scope.$on("projects:loaded",function(listener){return $el.addClass("hidden"),listener.stopPropagation()}),$scope.$on("project:loaded",function(ctx,newProject){return project=newProject,$el.hasClass("hidden")&&$el.removeClass("hidden"),project.videoconferenceUrl=videoConferenceUrl(project),renderMenuEntries($el,ctx.targetScope,project)})},{link:link}},module.directive("tgProjectMenu",["$log","$compile","$tgAuth","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","$tgConfig","$tgTemplate",ProjectMenuDirective])}.call(this),function(){var module;module=angular.module("taigaProject",[])}.call(this),function(){var RelatedTaskAssignedToInlineEditionDirective,RelatedTaskCreateButtonDirective,RelatedTaskCreateFormDirective,RelatedTaskRowDirective,RelatedTasksDirective,debounce,module,taiga,trim;taiga=this.taiga,trim=this.taiga.trim,debounce=this.taiga.debounce,module=angular.module("taigaRelatedTasks",[]),RelatedTaskRowDirective=function($repo,$compile,$confirm,$rootscope,$loading,$template){var link,templateEdit,templateView;return templateView=$template.get("task/related-task-row.html",!0),templateEdit=$template.get("task/related-task-row-edit.html",!0),link=function($scope,$el,$attrs,$model){var renderEdit,renderView,saveTask;return saveTask=debounce(2e3,function(task){var promise;return task.subject=$el.find("input").val(),$loading.start($el.find(".task-name")),promise=$repo.save(task),promise.then(function(){return function(){return $loading.finish($el.find(".task-name")),$confirm.notify("success"),$rootscope.$broadcast("related-tasks:update")}}(this)),promise.then(null,function(){return function(){return $loading.finish($el.find(".task-name")),$el.find("input").val(task.subject),$confirm.notify("error")}}(this)),promise}),renderEdit=function(task){return $el.html($compile(templateEdit({task:task}))($scope)),$el.on("keyup","input",function(event){return 13===event.keyCode?saveTask($model.$modelValue).then(function(){return renderView($model.$modelValue)}):27===event.keyCode?renderView($model.$modelValue):void 0}),$el.on("click",".icon-floppy",function(){return saveTask($model.$modelValue).then(function(){return renderView($model.$modelValue)})}),$el.on("click",".cancel-edit",function(){return renderView($model.$modelValue)})},renderView=function(task){var perms;return $el.off(),perms={modify_task:-1!==$scope.project.my_permissions.indexOf("modify_task"),delete_task:-1!==$scope.project.my_permissions.indexOf("delete_task")},$el.html($compile(templateView({task:task,perms:perms}))($scope)),$el.on("click",".icon-edit",function(){return renderEdit($model.$modelValue),$el.find("input").focus().select()}),$el.on("click",".delete-task",function(){var message,title;return task=$model.$modelValue,title="Delete Task",message=task.subject,$confirm.askOnDelete(title,message).then(function(finish){var promise;return promise=$repo.remove(task),promise.then(function(){return finish(),$confirm.notify("success"),$scope.$emit("related-tasks:delete")}),promise.then(null,function(){return $confirm.notify("error")})})})},$scope.$watch($attrs.ngModel,function(val){return val?renderView(val):void 0}),$scope.$on("related-tasks:assigned-to-changed",function(){return $rootscope.$broadcast("related-tasks:update")}),$scope.$on("related-tasks:status-changed",function(){return $rootscope.$broadcast("related-tasks:update")}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgRelatedTaskRow",["$tgRepo","$compile","$tgConfirm","$rootScope","$tgLoading","$tgTemplate",RelatedTaskRowDirective]),RelatedTaskCreateFormDirective=function($repo,$compile,$confirm,$tgmodel,$loading,$analytics,$template){var link,newTask,template;return template=$template.get("task/related-task-create-form.html",!0),newTask={subject:"",assigned_to:null},link=function($scope,$el){var createTask,render;return createTask=debounce(2e3,function(task){var promise;return task.subject=$el.find("input").val(),task.assigned_to=$scope.newTask.assigned_to,task.status=$scope.newTask.status,$scope.newTask.status=$scope.project.default_task_status,$scope.newTask.assigned_to=null,$loading.start($el.find(".task-name")),promise=$repo.create("tasks",task),promise.then(function(){return $analytics.trackEvent("task","create","create task on userstory",1),$loading.finish($el.find(".task-name")),$scope.$emit("related-tasks:add"),$confirm.notify("success")}),promise.then(null,function(){return $el.find("input").val(task.subject),$loading.finish($el.find(".task-name")),$confirm.notify("error")}),promise}),render=function(){return $el.off(),$el.html($compile(template())($scope)),$el.find("input").focus().select(),$el.addClass("active"),$el.on("keyup","input",function(event){return 13===event.keyCode?createTask(newTask).then(function(){return render()}):27===event.keyCode?$el.html(""):void 0}),$el.on("click",".icon-delete",function(){return $el.html("")}),$el.on("click",".icon-floppy",function(){return createTask(newTask).then(function(){return $el.html("")})})},taiga.bindOnce($scope,"us",function(){return newTask.status=$scope.project.default_task_status,newTask.project=$scope.project.id,newTask.user_story=$scope.us.id,$scope.newTask=$tgmodel.make_model("tasks",newTask),$el.html("")}),$scope.$on("related-tasks:show-form",function(){return render()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskCreateForm",["$tgRepo","$compile","$tgConfirm","$tgModel","$tgLoading","$tgAnalytics","$tgTemplate",RelatedTaskCreateFormDirective]),RelatedTaskCreateButtonDirective=function(){var link,template;return template=_.template(''),link=function($scope,$el){return $scope.$watch("project",function(val){return val?($el.off(),$el.html(-1!==$scope.project.my_permissions.indexOf("add_task")?template():""),$el.on("click",".icon",function(){return $scope.$emit("related-tasks:add-new-clicked")})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskCreateButton",["$tgRepo","$compile","$tgConfirm","$tgModel",RelatedTaskCreateButtonDirective]),RelatedTasksDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){var loadTasks;return loadTasks=function(){return $rs.tasks.list($scope.projectId,null,$scope.usId).then(function(){return function(tasks){return $scope.tasks=tasks,tasks}}(this))},$scope.$on("related-tasks:add",function(){return loadTasks().then(function(){return $rootscope.$broadcast("related-tasks:update")})}),$scope.$on("related-tasks:delete",function(){return loadTasks().then(function(){return $rootscope.$broadcast("related-tasks:update")})}),$scope.$on("related-tasks:add-new-clicked",function(){return $scope.$broadcast("related-tasks:show-form")}),taiga.bindOnce($scope,"us",function(){return loadTasks()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTasks",["$tgRepo","$tgResources","$rootScope",RelatedTasksDirective]),RelatedTaskAssignedToInlineEditionDirective=function($repo,$rootscope){var link,template;return template=_.template('<%- name %>\n
    <%- name %>
    '),link=function($scope,$el,$attrs){var $ctrl,autoSave,notAutoSave,task,updateRelatedTask;return updateRelatedTask=function(task){var ctx,member;return ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=$scope.usersById[task.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name_display),$el.find(".avatar").html(template(ctx)),$el.find(".task-assignedto").attr("title",ctx.name)},$ctrl=$el.controller(),task=$scope.$eval($attrs.tgRelatedTaskAssignedToInlineEdition),notAutoSave=$scope.$eval($attrs.notAutoSave),autoSave=!notAutoSave,updateRelatedTask(task),$el.on("click",".task-assignedto",function(){return $rootscope.$broadcast("assigned-to:add",task)}),taiga.bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_task")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("assigned-to:added",debounce(2e3,function(){return function(ctx,userId,updatedRelatedTask){return updatedRelatedTask.id===task.id?(updatedRelatedTask.assigned_to=userId,autoSave&&$repo.save(updatedRelatedTask).then(function(){return $scope.$emit("related-tasks:assigned-to-changed")}),updateRelatedTask(updatedRelatedTask)):void 0}}(this))),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskAssignedToInlineEdition",["$tgRepo","$rootScope",RelatedTaskAssignedToInlineEditionDirective])}.call(this),function(){var ResourcesService,initResources,initUrls,module,taiga,urls,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,ResourcesService=function(_super){function ResourcesService(){return ResourcesService.__super__.constructor.apply(this,arguments)}return __extends(ResourcesService,_super),ResourcesService}(taiga.Service),urls={auth:"/auth","auth-register":"/auth/register",invitations:"/invitations",permissions:"/permissions",roles:"/roles",projects:"/projects",memberships:"/memberships","notify-policies":"/notify-policies","bulk-create-memberships":"/memberships/bulk_create",milestones:"/milestones",userstories:"/userstories","bulk-create-us":"/userstories/bulk_create","bulk-update-us-backlog-order":"/userstories/bulk_update_backlog_order","bulk-update-us-sprint-order":"/userstories/bulk_update_sprint_order","bulk-update-us-kanban-order":"/userstories/bulk_update_kanban_order","userstories-restore":"/userstories/%s/restore",tasks:"/tasks","bulk-create-tasks":"/tasks/bulk_create","bulk-update-task-taskboard-order":"/tasks/bulk_update_taskboard_order","tasks-restore":"/tasks/%s/restore",issues:"/issues","bulk-create-issues":"/issues/bulk_create","issues-restore":"/issues/%s/restore",wiki:"/wiki","wiki-restore":"/wiki/%s/restore","wiki-links":"/wiki-links","choices/userstory-statuses":"/userstory-statuses","choices/userstory-statuses/bulk-update-order":"/userstory-statuses/bulk_update_order","choices/points":"/points","choices/points/bulk-update-order":"/points/bulk_update_order","choices/task-statuses":"/task-statuses","choices/task-statuses/bulk-update-order":"/task-statuses/bulk_update_order","choices/issue-statuses":"/issue-statuses","choices/issue-statuses/bulk-update-order":"/issue-statuses/bulk_update_order","choices/issue-types":"/issue-types","choices/issue-types/bulk-update-order":"/issue-types/bulk_update_order","choices/priorities":"/priorities","choices/priorities/bulk-update-order":"/priorities/bulk_update_order","choices/severities":"/severities","choices/severities/bulk-update-order":"/severities/bulk_update_order",search:"/search",sites:"/sites","project-templates":"/project-templates","site-members":"/site-members","site-projects":"/site-projects",users:"/users","users-password-recovery":"/users/password_recovery","users-change-password-from-recovery":"/users/change_password_from_recovery","users-change-password":"/users/change_password","users-change-email":"/users/change_email","users-cancel-account":"/users/cancel","user-storage":"/user-storage",resolver:"/resolver","userstory-statuses":"/userstory-statuses",points:"/points","task-statuses":"/task-statuses","issue-statuses":"/issue-statuses","issue-types":"/issue-types",priorities:"/priorities",severities:"/severities","project-modules":"/projects/%s/modules",webhooks:"/webhooks","webhooks-test":"/webhooks/%s/test",webhooklogs:"/webhooklogs","webhooklogs-resend":"/webhooklogs/%s/resend","history/us":"/history/userstory","history/issue":"/history/issue","history/task":"/history/task","history/wiki":"/history/wiki","attachments/us":"/userstories/attachments","attachments/issue":"/issues/attachments","attachments/task":"/tasks/attachments","attachments/wiki_page":"/wiki/attachments",feedback:"/feedback",exporter:"/exporter",importer:"/importer/load_dump"},initUrls=function($log,$urls){return $log.debug("Initialize api urls"),$urls.update(urls)},initResources=function($log,$rs){var provider,providers,_i,_len,_results;for($log.debug("Initialize resources"),providers=_.toArray(arguments).slice(2),_results=[],_i=0,_len=providers.length;_len>_i;_i++)provider=providers[_i],_results.push(provider($rs));return _results},module=angular.module("taigaResources",["taigaBase"]),module.service("$tgResources",ResourcesService),module.run(["$log","$tgUrls",initUrls]),module.run(["$log","$tgResources","$tgProjectsResourcesProvider","$tgMembershipsResourcesProvider","$tgNotifyPoliciesResourcesProvider","$tgInvitationsResourcesProvider","$tgRolesResourcesProvider","$tgUserSettingsResourcesProvider","$tgSprintsResourcesProvider","$tgUserstoriesResourcesProvider","$tgTasksResourcesProvider","$tgIssuesResourcesProvider","$tgWikiResourcesProvider","$tgSearchResourcesProvider","$tgAttachmentsResourcesProvider","$tgMdRenderResourcesProvider","$tgHistoryResourcesProvider","$tgKanbanResourcesProvider","$tgModulesResourcesProvider","$tgWebhooksResourcesProvider","$tgWebhookLogsResourcesProvider",initResources]) +}.call(this),function(){var SearchBoxDirective,SearchController,SearchDirective,bindOnce,debounce,debounceLeading,groupBy,mixOf,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,mixOf=this.taiga.mixOf,debounceLeading=this.taiga.debounceLeading,trim=this.taiga.trim,debounce=this.taiga.debounce,module=angular.module("taigaSearch",[]),SearchController=function(_super){function SearchController(scope,repo,rs,params,q,location,appTitle,navUrls,tgLoader){var loadSearchData,promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.tgLoader=tgLoader,this.scope.sectionName="Search",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Search")}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.searchTerm="",loadSearchData=debounceLeading(100,function(_this){return function(t){return _this.loadSearchData(t)}}(this)),this.scope.$watch("searchTerm",function(_this){return function(term){return term?loadSearchData(term):_this.tgLoader.pageLoaded()}}(this))}return __extends(SearchController,_super),SearchController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","tgLoader"],SearchController.prototype.loadFilters=function(){var defered;return defered=this.q.defer(),defered.resolve(),defered.promise},SearchController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issueStatusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.taskStatusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),project}}(this))},SearchController.prototype.loadSearchData=function(term){var promise;return promise=this.rs.search["do"](this.scope.projectId,term).then(function(_this){return function(data){return _this.scope.searchResults=data,data}}(this)),promise["finally"](function(_this){return function(){return _this.tgLoader.pageLoaded()}}(this)),promise},SearchController.prototype.loadInitialData=function(){return this.loadProject().then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.fillUsersAndRoles(project.users,project.roles)}}(this))},SearchController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("SearchController",SearchController),SearchBoxDirective=function($lightboxService,$navurls,$location,$route){var link;return link=function($scope,$el){var project,submit;return project=null,submit=debounce(2e3,function(){return function(event){var form,text,url;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?(text=$el.find("#search-text").val(),url=$navurls.resolve("project-search",{project:project.slug}),$lightboxService.close($el),$scope.$apply(function(){return $location.path(url),$location.search("text",text).path(url),$route.reload()})):void 0}}(this)),$scope.$on("search-box:show",function(ctx,newProject){return project=newProject,$lightboxService.open($el),$el.find("#search-text").val("")}),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgSearchBox",["lightboxService","$tgNavUrls","$tgLocation","$route",SearchBoxDirective]),SearchDirective=function($log,$compile,$templatecache,$routeparams,$location){var link,linkTable;return linkTable=function($scope,$el){var getActiveSection,lastSeatchResults,markSectionTabActive,renderFilterTabs,renderTableContent,tabsDom,templates;return tabsDom=$el.find("section.search-filter"),lastSeatchResults=null,getActiveSection=function(data){var maxVal,name,selectedSectionData,selectedSectionName,value;maxVal=0,selectedSectionName=null,selectedSectionData=null;for(name in data)value=data[name],"count"!==name&&value.length>maxVal&&(maxVal=value.length,selectedSectionName=name,selectedSectionData=value);return 0===maxVal?{name:"userstories",value:[]}:{name:selectedSectionName,value:selectedSectionData}},renderFilterTabs=function(data){var name,value,_results;_results=[];for(name in data)value=data[name],"count"!==name&&_results.push(tabsDom.find("li."+name+" .num").html(value.length));return _results},markSectionTabActive=function(section){return tabsDom.find("a.active").removeClass("active"),tabsDom.find("li."+section.name+" a").addClass("active")},templates={issues:$templatecache.get("search-issues"),tasks:$templatecache.get("search-tasks"),userstories:$templatecache.get("search-userstories"),wikipages:$templatecache.get("search-wikipages")},renderTableContent=function(section){var element,oldElements,oldScope,scope,template;return oldElements=$el.find(".search-result-table").children(),oldScope=oldElements.scope(),oldScope&&(oldScope.$destroy(),oldElements.remove()),scope=$scope.$new(),scope[section.name]=section.value,template=angular.element.parseHTML(trim(templates[section.name])),element=$compile(template)(scope),$el.find(".search-result-table").html(element)},$scope.$watch("searchResults",function(data){var activeSection;return lastSeatchResults=data,activeSection=getActiveSection(data),renderFilterTabs(data),renderTableContent(activeSection),markSectionTabActive(activeSection)}),$scope.$watch("searchTerm",function(searchTerm){return searchTerm?$location.search("text",searchTerm):void 0}),$el.on("click",".search-filter li > a",function(event){var section,sectionData,sectionName,target;return event.preventDefault(),target=angular.element(event.currentTarget),sectionName=target.parent().data("name"),sectionData=lastSeatchResults[sectionName],section={name:sectionName,value:sectionData},$scope.$apply(function(){return renderTableContent(section),markSectionTabActive(section)})})},link=function($scope,$el,$attrs){var $ctrl,searchText;return $ctrl=$el.controller(),linkTable($scope,$el,$attrs,$ctrl),searchText=$routeparams.text,$scope.$watch("projectId",function(projectId){return null!=projectId?$scope.searchTerm=searchText:void 0})},{link:link}},module.directive("tgSearch",["$log","$compile","$templateCache","$routeParams","$tgLocation",SearchDirective])}.call(this),function(){var module;module=angular.module("taigaTaskboard",[])}.call(this),function(){var module;module=angular.module("taigaTasks",[])}.call(this),function(){var module;module=angular.module("taigaTeam",[])}.call(this),function(){var module;module=angular.module("taigaUserSettings",[])}.call(this),function(){var module;module=angular.module("taigaUserStories",[])}.call(this),function(){var module;module=angular.module("taigaWiki",[])}.call(this),function(){var AnalyticsService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,module=angular.module("taigaCommon"),AnalyticsService=function(_super){function AnalyticsService(rootscope,log,config,win,doc,location){var conf;this.rootscope=rootscope,this.log=log,this.config=config,this.win=win,this.doc=doc,this.location=location,this.initialized=!1,conf=this.config.get("analytics",{}),this.accountId=conf.accountId,this.pageEvent=conf.pageEvent||"$routeChangeSuccess",this.trackRoutes=conf.trackRoutes||!0,this.ignoreFirstPageLoad=conf.ignoreFirstPageLoad||!1}return __extends(AnalyticsService,_super),AnalyticsService.$inject=["$rootScope","$log","$tgConfig","$window","$document","$location"],AnalyticsService.prototype.initialize=function(){return this.accountId?(this.injectAnalytics(),this.win.ga("create",this.accountId,"auto"),this.win.ga("require","displayfeatures"),this.trackRoutes&&!this.ignoreFirstPageLoad&&this.win.ga("send","pageview",this.getUrl()),this.trackRoutes&&this.rootscope.$on(this.pageEvent,function(_this){return function(){return _this.trackPage(_this.getUrl(),"Taiga")}}(this)),this.initialized=!0):void this.log.debug("Analytics: no acount id provided. Disabling.")},AnalyticsService.prototype.getUrl=function(){return this.location.path()},AnalyticsService.prototype.injectAnalytics=function(){var fn;return(fn=function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r,i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date,a=s.createElement(o),m=s.getElementsByTagName(o)[0],a.async=1,a.src=g,m.parentNode.insertBefore(a,m)})(window,document,"script","//www.google-analytics.com/analytics.js","ga")},AnalyticsService.prototype.trackPage=function(url,title){return this.initialized&&this.win.ga?(title=title||this.doc[0].title,this.win.ga("send","pageview",{page:url,title:title})):void 0},AnalyticsService.prototype.trackEvent=function(category,action,label,value){return this.initialized&&this.win.ga?this.win.ga("send","event",category,action,label,value):void 0},AnalyticsService}(taiga.Service),module.service("$tgAnalytics",AnalyticsService)}.call(this),function(){var AttachmentDirective,AttachmentsController,AttachmentsDirective,bindMethods,bindOnce,module,sizeFormat,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,bindOnce=this.taiga.bindOnce,bindMethods=this.taiga.bindMethods,module=angular.module("taigaCommon"),AttachmentsController=function(_super){function AttachmentsController(scope,rootscope,repo,rs,confirm,q){this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.rs=rs,this.confirm=confirm,this.q=q,bindMethods(this),this.type=null,this.objectId=null,this.projectId=null,this.uploadingAttachments=[],this.attachments=[],this.attachmentsCount=0,this.deprecatedAttachmentsCount=0,this.showDeprecated=!1}return __extends(AttachmentsController,_super),AttachmentsController.$inject=["$scope","$rootScope","$tgRepo","$tgResources","$tgConfirm","$q"],AttachmentsController.prototype.initialize=function(type,objectId){return this.type=type,this.objectId=objectId,this.projectId=this.scope.projectId},AttachmentsController.prototype.loadAttachments=function(){var urlname;return this.objectId?(urlname="attachments/"+this.type,this.rs.attachments.list(urlname,this.objectId,this.projectId).then(function(_this){return function(attachments){return _this.attachments=_.sortBy(attachments,"order"),_this.updateCounters(),attachments}}(this))):this.attachments},AttachmentsController.prototype.updateCounters=function(){return this.attachmentsCount=this.attachments.length,this.deprecatedAttachmentsCount=_.filter(this.attachments,{is_deprecated:!0}).length},AttachmentsController.prototype._createAttachment=function(attachment){var promise,urlName;return urlName="attachments/"+this.type,promise=this.rs.attachments.create(urlName,this.projectId,this.objectId,attachment),promise=promise.then(function(_this){return function(data){var index;return data.isCreatedRightNow=!0,index=_this.uploadingAttachments.indexOf(attachment),_this.uploadingAttachments.splice(index,1),_this.attachments.push(data),_this.rootscope.$broadcast("attachment:create")}}(this)),promise=promise.then(null,function(_this){return function(data){var index;return 413===data.status&&_this.scope.$emit("attachments:size-error"),index=_this.uploadingAttachments.indexOf(attachment),_this.uploadingAttachments.splice(index,1),_this.confirm.notify("error","We have not been able to upload '"+attachment.name+"'. "+data.data._error_message),_this.q.reject(data)}}(this))},AttachmentsController.prototype.createAttachments=function(attachments){var promises;return promises=_.map(attachments,function(_this){return function(x){return _this._createAttachment(x)}}(this)),this.q.all(promises).then(function(_this){return function(){return _this.updateCounters()}}(this))},AttachmentsController.prototype.addUploadingAttachments=function(attachments){return this.uploadingAttachments=_.union(this.uploadingAttachments,attachments)},AttachmentsController.prototype.reorderAttachment=function(attachment,newIndex){var oldIndex;return oldIndex=this.attachments.indexOf(attachment),oldIndex!==newIndex?(this.attachments.splice(oldIndex,1),this.attachments.splice(newIndex,0,attachment),_.each(this.attachments,function(x,i){return x.order=i+1})):void 0},AttachmentsController.prototype.updateAttachment=function(attachment){var onError,onSuccess;return onSuccess=function(_this){return function(){return _this.updateCounters(),_this.rootscope.$broadcast("attachment:edit")}}(this),onError=function(_this){return function(response){return 413===response.status&&$scope.$emit("attachments:size-error"),_this.confirm.notify("error"),_this.q.reject()}}(this),this.repo.save(attachment).then(onSuccess,onError)},AttachmentsController.prototype.saveAttachments=function(){return this.repo.saveAll(this.attachments).then(null,function(_this){return function(){var item,_i,_len,_ref;for(_ref=_this.attachments,_i=0,_len=_ref.length;_len>_i;_i++)item=_ref[_i],item.revert();return _this.attachments=_.sorBy(_this.attachments,"order")}}(this))},AttachmentsController.prototype.removeAttachment=function(attachment){var message,title;return title="Delete attachment",message="the attachment '"+attachment.name+"'",this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var onError,onSuccess;return onSuccess=function(){var index;return finish(),index=_this.attachments.indexOf(attachment),_this.attachments.splice(index,1),_this.updateCounters(),_this.rootscope.$broadcast("attachment:delete")},onError=function(){return finish(!1),_this.confirm.notify("error",null,"We have not been able to delete "+message+"."),_this.q.reject()},_this.repo.remove(attachment).then(onSuccess,onError)}}(this))},AttachmentsController.prototype.filterAttachments=function(item){return this.showDeprecated?!0:!item.is_deprecated},AttachmentsController}(taiga.Controller),AttachmentsDirective=function($config,$confirm,$templates){var link,template,templateFn;return template=$templates.get("attachment/attachments.html",!0),link=function($scope,$el,$attrs,$ctrls){var $ctrl,$model,showSizeInfo,tdom;return $ctrl=$ctrls[0],$model=$ctrls[1],bindOnce($scope,$attrs.ngModel,function(value){return $ctrl.initialize($attrs.type,value.id),$ctrl.loadAttachments()}),tdom=$el.find("div.attachment-body.sortable"),tdom.sortable({items:"div.single-attachment",handle:"a.settings.icon.icon-drag-v",containment:".attachments",dropOnEmpty:!0,scroll:!1,tolerance:"pointer",placeholder:"sortable-placeholder single-attachment"}),tdom.on("sortstop",function(event,ui){var attachment,newIndex;return attachment=ui.item.scope().attach,newIndex=ui.item.index(),$ctrl.reorderAttachment(attachment,newIndex),$ctrl.saveAttachments()}),showSizeInfo=function(){return $el.find(".size-info").removeClass("hidden")},$scope.$on("attachments:size-error",function(){return showSizeInfo()}),$el.on("change",".attachments-header input",function(event){var files;return files=_.toArray(event.target.files),files.length<1?void 0:$scope.$apply(function(){return $ctrl.addUploadingAttachments(files),$ctrl.createAttachments(files)})}),$el.on("click",".more-attachments",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $ctrl.showDeprecated=!$ctrl.showDeprecated}),target.find("span.text").addClass("hidden"),$ctrl.showDeprecated?(target.find("span[data-type=hide]").removeClass("hidden"),target.find("more-attachments-num").addClass("hidden")):(target.find("span[data-type=show]").removeClass("hidden"),target.find("more-attachments-num").removeClass("hidden"))}),$scope.$on("$destroy",function(){return $el.off()})},templateFn=function($el,$attrs){var ctx,maxFileSize,maxFileSizeMsg;return maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&(maxFileSize=sizeFormat(maxFileSize)),maxFileSizeMsg=maxFileSize?"Maximum upload size is "+maxFileSize:"",ctx={type:$attrs.type,maxFileSize:maxFileSize,maxFileSizeMsg:maxFileSizeMsg},template(ctx)},{require:["tgAttachments","ngModel"],controller:AttachmentsController,controllerAs:"ctrl",restrict:"AE",scope:!0,link:link,template:templateFn}},module.directive("tgAttachments",["$tgConfig","$tgConfirm","$tgTemplate",AttachmentsDirective]),AttachmentDirective=function($template){var link,template,templateEdit;return template=$template.get("attachment/attachment.html",!0),templateEdit=$template.get("attachment/attachment-edit.html",!0),link=function($scope,$el,$attrs,$ctrl){var attachment,render,saveAttachment;return render=function(attachment,edit){var ctx,html,modifyPermission,permissions;return null==edit&&(edit=!1),permissions=$scope.project.my_permissions,modifyPermission=permissions.indexOf("modify_"+$ctrl.type)>-1,ctx={id:attachment.id,name:attachment.name,created_date:moment(attachment.created_date).format("DD MMM YYYY [at] hh:mm"),url:attachment.url,size:sizeFormat(attachment.size),description:attachment.description,isDeprecated:attachment.is_deprecated,modifyPermission:modifyPermission},html=edit?templateEdit(ctx):template(ctx),$el.html(html),attachment.is_deprecated?($el.addClass("deprecated"),$el.find("input:checkbox").prop("checked",!0)):void 0},saveAttachment=function(){return attachment.description=$el.find("input[name='description']").val(),attachment.is_deprecated=$el.find("input[name='is-deprecated']").prop("checked"),$scope.$apply(function(){return $ctrl.updateAttachment(attachment).then(function(){return render(attachment,!1)})})},$el.on("click","a.editable-settings.icon-floppy",function(event){return event.preventDefault(),saveAttachment()}),$el.on("keyup","input[name=description]",function(event){return 13===event.keyCode?saveAttachment():27===event.keyCode?render(attachment,!1):void 0}),$el.on("click","a.editable-settings.icon-delete",function(event){return event.preventDefault(),render(attachment,!1)}),$el.on("click","a.settings.icon-edit",function(event){return event.preventDefault(),render(attachment,!0),$el.find("input[name='description']").focus().select()}),$el.on("click","a.settings.icon-delete",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.removeAttachment(attachment)})}),$scope.$on("$destroy",function(){return $el.off()}),attachment=$scope.$eval($attrs.tgAttachment),render(attachment,attachment.isCreatedRightNow),attachment.isCreatedRightNow?$el.find("input[name='description']").focus().select():void 0},{link:link,require:"^tgAttachments",restrict:"AE"}},module.directive("tgAttachment",["$tgTemplate",AttachmentDirective])}.call(this),function(){var AssignedToDirective,BlockButtonDirective,CreatedByDisplayDirective,DateRangeDirective,DateSelectorDirective,DeleteButtonDirective,EditableDescriptionDirective,EditableSubjectDirective,ListItemAssignedtoDirective,ListItemIssueStatusDirective,ListItemPriorityDirective,ListItemSeverityDirective,ListItemTaskStatusDirective,ListItemTypeDirective,ListItemUsStatusDirective,SprintProgressBarDirective,TgMainTitleDirective,TgProgressBarDirective,WatchersDirective,bindOnce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),DateRangeDirective=function(){var link,renderRange;return renderRange=function($el,first,second){var endDate,initDate;return initDate=moment(first).format("DD MMM YYYY"),endDate=moment(second).format("DD MMM YYYY"),$el.html(""+initDate+"-"+endDate)},link=function($scope,$el,$attrs){var first,second,_ref;return _ref=$attrs.tgDateRange.split(","),first=_ref[0],second=_ref[1],bindOnce($scope,first,function(valFirst){return bindOnce($scope,second,function(valSecond){return renderRange($el,valFirst,valSecond)})})},{link:link}},module.directive("tgDateRange",DateRangeDirective),DateSelectorDirective=function(){var link;return link=function($scope,$el,$attrs){var selectedDate;return selectedDate=null,$el.picker=new Pikaday({field:$el[0],format:"DD MMM YYYY",onSelect:function(){return function(date){return selectedDate=date}}(this),onOpen:function(){return function(){return null!=selectedDate?$el.picker.setDate(selectedDate):void 0}}(this)}),$scope.$watch($attrs.ngModel,function(val){return null!=val?$el.picker.setDate(val):void 0})},{link:link,require:"ngModel"}},module.directive("tgDateSelector",DateSelectorDirective),SprintProgressBarDirective=function(){var link,renderProgress;return renderProgress=function($el,percentage,visual_percentage){return $el.hasClass(".current-progress")?$el.css("width",""+percentage+"%"):($el.find(".current-progress").css("width",""+visual_percentage+"%"),$el.find(".number").html(""+percentage+" %"))},link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgSprintProgressbar,function(sprint){var closedPoints,percentage,totalPoints,visual_percentage;return closedPoints=sprint.closed_points,totalPoints=sprint.total_points,percentage=0,0!==totalPoints&&(percentage=Math.round(100*(closedPoints/totalPoints))),visual_percentage=0,0!==totalPoints&&(visual_percentage=Math.round(98*(closedPoints/totalPoints))),renderProgress($el,percentage,visual_percentage)})},{link:link}},module.directive("tgSprintProgressbar",SprintProgressBarDirective),CreatedByDisplayDirective=function($template){var link,template;return template=$template.get("common/components/created-by.html",!0),link=function($scope,$el,$attrs){var render;return render=function(model){var html,owner,_ref;return owner=(null!=(_ref=$scope.usersById)?_ref[model.owner]:void 0)||{full_name_display:"external user",photo:"/images/unnamed.png"},html=template({owner:owner,date:moment(model.created_date).format("DD MMM YYYY HH:mm")}),$el.html(html)},bindOnce($scope,$attrs.ngModel,function(model){return null!=model?render(model):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgCreatedByDisplay",["$tgTemplate",CreatedByDisplayDirective]),WatchersDirective=function($rootscope,$confirm,$repo,$qqueue,$template){var link,template;return template=$template.get("common/components/watchers.html",!0),link=function($scope,$el,$attrs,$model){var deleteWatcher,isEditable,renderWatchers,save;return isEditable=function(){var _ref,_ref1;return-1!==(null!=(_ref=$scope.project)&&null!=(_ref1=_ref.my_permissions)?_ref1.indexOf($attrs.requiredPerm):void 0)},save=$qqueue.bindAdd(function(){return function(watchers){var item,promise;return item=$model.$modelValue.clone(),item.watchers=watchers,$model.$setViewValue(item),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),watchers=_.map(watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $model.$modelValue.revert()})}}(this)),deleteWatcher=$qqueue.bindAdd(function(){return function(watcherIds){var item,promise;return item=$model.$modelValue.clone(),item.watchers=watcherIds,$model.$setViewValue(item),promise=$repo.save($model.$modelValue),promise.then(function(){var watchers;return $confirm.notify("success"),watchers=_.map(item.watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return item.revert(),$confirm.notify("error")})}}(this)),renderWatchers=function(watchers){var ctx,html;return ctx={watchers:watchers,isEditable:isEditable()},html=template(ctx),$el.html(html),isEditable()&&0===watchers.length?($el.find(".title").text("Add watchers"),$el.find(".watchers-header").addClass("no-watchers")):void 0},$el.on("click",".icon-delete",function(event){var message,target,title,watcherId;return event.preventDefault(),isEditable()?(target=angular.element(event.currentTarget),watcherId=target.data("watcher-id"),title="Delete watcher",message=$scope.usersById[watcherId].full_name_display,$confirm.askOnDelete(title,message).then(function(){return function(finish){var watcherIds;return finish(),watcherIds=_.clone($model.$modelValue.watchers,!1),watcherIds=_.pull(watcherIds,watcherId),deleteWatcher(watcherIds)}}(this))):void 0}),$el.on("click",".add-watcher",function(event){return event.preventDefault(),isEditable()?$scope.$apply(function(){return $rootscope.$broadcast("watcher:add",$model.$modelValue)}):void 0}),$scope.$on("watcher:added",function(ctx,watcherId){var watchers;return watchers=_.clone($model.$modelValue.watchers,!1),watchers.push(watcherId),watchers=_.uniq(watchers),save(watchers)}),$scope.$watch($attrs.ngModel,function(item){var watchers;if(null!=item)return watchers=_.map(item.watchers,function(watcherId){return $scope.usersById[watcherId]}),renderWatchers(watchers)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgWatchers",["$rootScope","$tgConfirm","$tgRepo","$tgQqueue","$tgTemplate",WatchersDirective]),AssignedToDirective=function($rootscope,$confirm,$repo,$loading,$qqueue,$template){var link,template;return template=$template.get("common/components/assigned-to.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,renderAssignedTo,save;return isEditable=function(){var _ref,_ref1;return-1!==(null!=(_ref=$scope.project)&&null!=(_ref1=_ref.my_permissions)?_ref1.indexOf($attrs.requiredPerm):void 0)},save=$qqueue.bindAdd(function(){return function(userId){var promise;return $model.$modelValue.assigned_to=userId,$loading.start($el),promise=$repo.save($model.$modelValue),promise.then(function(){return $loading.finish($el),$confirm.notify("success"),renderAssignedTo($model.$modelValue),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $model.$modelValue.revert(),$confirm.notify("error"),$loading.finish($el)}),promise}}(this)),renderAssignedTo=function(issue){var assignedTo,assignedToId,ctx,html;return assignedToId=null!=issue?issue.assigned_to:void 0,assignedTo=null!=assignedToId?$scope.usersById[assignedToId]:null,ctx={assignedTo:assignedTo,isEditable:isEditable()},html=template(ctx),$el.html(html)},$el.on("click",".user-assigned",function(event){return event.preventDefault(),isEditable()?$scope.$apply(function(){return $rootscope.$broadcast("assigned-to:add",$model.$modelValue)}):void 0}),$el.on("click",".icon-delete",function(event){var title;return event.preventDefault(),isEditable()?(title="Are you sure you want to leave it unassigned?",$confirm.ask(title).then(function(){return function(finish){return finish(),$model.$modelValue.assigned_to=null,save(null)}}(this))):void 0}),$scope.$on("assigned-to:added",function(ctx,userId,item){return item.id===$model.$modelValue.id?save(userId):void 0}),$scope.$watch($attrs.ngModel,function(instance){return renderAssignedTo(instance)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgAssignedTo",["$rootScope","$tgConfirm","$tgRepo","$tgLoading","$tgQqueue","$tgTemplate",AssignedToDirective]),BlockButtonDirective=function($rootscope,$loading,$template){var link,template;return template=$template.get("common/components/block-button.html"),link=function($scope,$el,$attrs,$model){var isEditable;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},$scope.$watch($attrs.ngModel,function(item){return item?(isEditable()&&$el.find(".item-block").addClass("editable"),item.is_blocked?($el.find(".item-block").hide(),$el.find(".item-unblock").show()):($el.find(".item-block").show(),$el.find(".item-unblock").hide())):void 0}),$el.on("click",".item-block",function(event){return event.preventDefault(),$rootscope.$broadcast("block",$model.$modelValue)}),$el.on("click",".item-unblock",function(event){var finish;return event.preventDefault(),$loading.start($el.find(".item-unblock")),finish=function(){return $loading.finish($el.find(".item-unblock"))},$rootscope.$broadcast("unblock",$model.$modelValue,finish)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgBlockButton",["$rootScope","$tgLoading","$tgTemplate",BlockButtonDirective]),DeleteButtonDirective=function($log,$repo,$confirm,$location,$template){var link,template;return template=$template.get("common/components/delete-button.html"),link=function($scope,$el,$attrs,$model){return $attrs.onDeleteGoToUrl?$attrs.onDeleteTitle?($el.on("click",".button",function(){var subtitle,title;return title=$scope.$eval($attrs.onDeleteTitle),subtitle=$model.$modelValue.subject,$confirm.askOnDelete(title,subtitle).then(function(){return function(finish){var promise;return promise=$repo.remove($model.$modelValue),promise.then(function(){var url;return finish(),url=$scope.$eval($attrs.onDeleteGoToUrl),$location.path(url)}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})}}(this))}),$scope.$on("$destroy",function(){return $el.off()})):$log.error("DeleteButtonDirective requires on-delete-title set in scope."):$log.error("DeleteButtonDirective requires on-delete-go-to-url set in scope.")},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgDeleteButton",["$log","$tgRepo","$tgConfirm","$tgLocation","$tgTemplate",DeleteButtonDirective]),EditableSubjectDirective=function($rootscope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("common/components/editable-subject.html"),link=function($scope,$el,$attrs,$model){var isEditable,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},save=$qqueue.bindAdd(function(){return function(subject){var promise;return $model.$modelValue.subject=subject,$loading.start($el.find(".save-container")),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$el.find(".edit-subject").hide(),$el.find(".view-subject").show()}),promise.then(null,function(){return $confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find(".save-container"))}),promise}}(this)),$el.click(function(){return isEditable()?($el.find(".edit-subject").show(),$el.find(".view-subject").hide(),$el.find("input").focus()):void 0}),$el.on("click",".save",function(){var subject;return subject=$scope.item.subject,save(subject)}),$el.on("keyup","input",function(event){var subject;return 13===event.keyCode?(subject=$scope.item.subject,save(subject)):27===event.keyCode?($scope.$apply(function(){return function(){return $model.$modelValue.revert()}}(this)),$el.find("div.edit-subject").hide(),$el.find("div.view-subject").show()):void 0}),$el.find("div.edit-subject").hide(),$el.find("div.view-subject span.edit").hide(),$scope.$watch($attrs.ngModel,function(value){return value?($scope.item=value,isEditable()?void 0:$el.find(".view-subject .edit").remove()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgEditableSubject",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",EditableSubjectDirective]),EditableDescriptionDirective=function($rootscope,$repo,$confirm,$compile,$loading,$selectedText,$qqueue,$template){var link,noDescriptionMegEditMode,noDescriptionMegReadMode,template; +return template=$template.get("common/components/editable-description.html"),noDescriptionMegEditMode=$template.get("common/components/editable-description-msg-edit-mode.html"),noDescriptionMegReadMode=$template.get("common/components/editable-description-msg-read-mode.html"),link=function($scope,$el,$attrs,$model){var isEditable,save;return $el.find(".edit-description").hide(),$el.find(".view-description .edit").hide(),isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},save=$qqueue.bindAdd(function(){return function(description){var promise;return $model.$modelValue.description=description,$loading.start($el.find(".save-container")),promise=$repo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$el.find(".edit-description").hide(),$el.find(".view-description").show()}),promise.then(null,function(){return $confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find(".save-container"))})}}(this)),$el.on("mouseup",".view-description",function(event){var target;return target=angular.element(event.target),!isEditable()||target.is("a")||$selectedText.get().length?void 0:($el.find(".edit-description").show(),$el.find(".view-description").hide(),$el.find("textarea").focus())}),$el.on("click",".save",function(){var description;return description=$scope.item.description,save(description)}),$el.on("keydown","textarea",function(event){return 27===event.keyCode?($scope.$apply(function(){return function(){return $scope.item.revert()}}(this)),$el.find(".edit-description").hide(),$el.find(".view-description").show()):void 0}),$scope.$watch($attrs.ngModel,function(value){return value?($scope.item=value,isEditable()?($el.find(".view-description .edit").show(),$el.find(".view-description .us-content").addClass("editable"),$scope.noDescriptionMsg=noDescriptionMegEditMode):$scope.noDescriptionMsg=noDescriptionMegReadMode):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",template:template}},module.directive("tgEditableDescription",["$rootScope","$tgRepo","$tgConfirm","$compile","$tgLoading","$selectedText","$tgQqueue","$tgTemplate",EditableDescriptionDirective]),ListItemIssueStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var issue;return issue=$scope.$eval($attrs.tgListitemIssueStatus),bindOnce($scope,"issueStatusById",function(issueStatusById){return $el.html(issueStatusById[issue.status].name)})},{link:link}},ListItemTaskStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var task;return task=$scope.$eval($attrs.tgListitemTaskStatus),bindOnce($scope,"taskStatusById",function(taskStatusById){return $el.html(taskStatusById[task.status].name)})},{link:link}},ListItemUsStatusDirective=function(){var link;return link=function($scope,$el,$attrs){var us;return us=$scope.$eval($attrs.tgListitemUsStatus),bindOnce($scope,"usStatusById",function(usStatusById){return $el.html(usStatusById[us.status].name)})},{link:link}},ListItemAssignedtoDirective=function($template){var link,template;return template=$template.get("common/components/list-item-assigned-to-avatar.html",!0),link=function($scope,$el,$attrs){return bindOnce($scope,"membersById",function(membersById){var ctx,item,member;return item=$scope.$eval($attrs.tgListitemAssignedto),ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=membersById[item.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name),$el.html(template(ctx))})},{link:link}},module.directive("tgListitemAssignedto",["$tgTemplate",ListItemAssignedtoDirective]),ListItemPriorityDirective=function(){var link;return link=function($scope,$el,$attrs){var render;return render=function(priorityById,issue){var domNode,priority;return priority=priorityById[issue.priority],domNode=$el.find(".level"),domNode.css("background-color",priority.color),domNode.attr("title",priority.name)},bindOnce($scope,"priorityById",function(priorityById){var issue;return issue=$scope.$eval($attrs.tgListitemPriority),render(priorityById,issue)}),$scope.$watch($attrs.tgListitemPriority,function(issue){return render($scope.priorityById,issue)})},{link:link,templateUrl:"common/components/level.html"}},module.directive("tgListitemPriority",ListItemPriorityDirective),ListItemSeverityDirective=function(){var link;return link=function($scope,$el,$attrs){var render;return render=function(severityById,issue){var domNode,severity;return severity=severityById[issue.severity],domNode=$el.find(".level"),domNode.css("background-color",severity.color),domNode.attr("title",severity.name)},bindOnce($scope,"severityById",function(severityById){var issue;return issue=$scope.$eval($attrs.tgListitemSeverity),render(severityById,issue)}),$scope.$watch($attrs.tgListitemSeverity,function(issue){return render($scope.severityById,issue)})},{link:link,templateUrl:"common/components/level.html"}},ListItemTypeDirective=function(){var link;return link=function($scope,$el,$attrs){var render;return render=function(issueTypeById,issue){var domNode,type;return type=issueTypeById[issue.type],domNode=$el.find(".level"),domNode.css("background-color",type.color),domNode.attr("title",type.name)},bindOnce($scope,"issueTypeById",function(issueTypeById){var issue;return issue=$scope.$eval($attrs.tgListitemType),render(issueTypeById,issue)}),$scope.$watch($attrs.tgListitemType,function(issue){return render($scope.issueTypeById,issue)})},{link:link,templateUrl:"common/components/level.html"}},TgProgressBarDirective=function($template){var link,render,template;return template=$template.get("common/components/progress-bar.html",!0),render=function(el,percentage){return el.html(template({percentage:percentage}))},link=function($scope,$el,$attrs){var element;return element=angular.element($el),$scope.$watch($attrs.tgProgressBar,function(percentage){return percentage=_.max([0,percentage]),percentage=_.min([100,percentage]),render($el,percentage)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgProgressBar",["$tgTemplate",TgProgressBarDirective]),TgMainTitleDirective=function($template){var link,render,template;return template=$template.get("common/components/main-title.html",!0),render=function(el,projectName,sectionName){return el.html(template({projectName:projectName,sectionName:sectionName}))},link=function($scope,$el){var element;return element=angular.element($el),$scope.$watch("project",function(project){return project?render($el,project.name,$scope.sectionName):void 0}),$scope.$on("project:loaded",function(){return function(ctx,project){return render($el,project.name,$scope.sectionName)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgMainTitle",["$tgTemplate",TgMainTitleDirective]),module.directive("tgListitemType",ListItemTypeDirective),module.directive("tgListitemIssueStatus",ListItemIssueStatusDirective),module.directive("tgListitemSeverity",ListItemSeverityDirective),module.directive("tgListitemTaskStatus",ListItemTaskStatusDirective),module.directive("tgListitemUsStatus",ListItemUsStatusDirective)}.call(this),function(){var ConfirmService,NOTIFICATION_MSG,bindMethods,cancelTimeout,debounce,module,taiga,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,timeout=this.taiga.timeout,cancelTimeout=this.taiga.cancelTimeout,debounce=this.taiga.debounce,bindMethods=this.taiga.bindMethods,NOTIFICATION_MSG={success:{title:"Everything is ok",message:"Our Oompa Loompas saved all your changes!"},error:{title:"Oops, something happened...",message:"Our Oompa Loompas are sad, your changes were not saved!"},"light-error":{title:"Oops, something happened...",message:"Our Oompa Loompas are sad, your changes were not saved!"}},ConfirmService=function(_super){function ConfirmService(q,lightboxService,loading){this.q=q,this.lightboxService=lightboxService,this.loading=loading,bindMethods(this)}return __extends(ConfirmService,_super),ConfirmService.$inject=["$q","lightboxService","$tgLoading"],ConfirmService.prototype.hide=function(el){return el?(this.lightboxService.close(el),el.off(".confirm-dialog")):void 0},ConfirmService.prototype.ask=function(title,subtitle,message,lightboxSelector){var defered,el;return null==lightboxSelector&&(lightboxSelector=".lightbox-generic-ask"),el=angular.element(lightboxSelector),el.find("h2.title").html(title),el.find("span.subtitle").html(subtitle),el.find("span.message").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",debounce(2e3,function(_this){return function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),_this.loading.start(target),defered.resolve(function(ok){return null==ok&&(ok=!0),_this.loading.finish(target),ok?_this.hide(el):void 0})}}(this))),el.on("click.confirm-dialog","a.button-red",function(_this){return function(event){return event.preventDefault(),defered.reject(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.askOnDelete=function(title,message){return this.ask(title,"Are you sure you want to delete?",message)},ConfirmService.prototype.askChoice=function(title,subtitle,choices,replacement,warning,lightboxSelector){var choicesField,defered,el;return null==lightboxSelector&&(lightboxSelector=".lightbox-ask-choice"),el=angular.element(lightboxSelector),el.find(".title").html(title),el.find(".subtitle").html(subtitle),replacement?el.find(".replacement").html(replacement):el.find(".replacement").remove(),warning?el.find(".warning").html(warning):el.find(".warning").remove(),choicesField=el.find(".choices"),choicesField.html(""),_.each(choices,function(value,key){return choicesField.append(angular.element(""))}),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",debounce(2e3,function(_this){return function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),_this.loading.start(target),defered.resolve({selected:choicesField.val(),finish:function(){return _this.loading.finish(target),_this.hide(el)}})}}(this))),el.on("click.confirm-dialog","a.button-red",function(_this){return function(event){return event.preventDefault(),defered.reject(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.error=function(message){var defered,el;return el=angular.element(".lightbox-generic-error"),el.find("h2.title").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),el.on("click.confirm-dialog","a.close",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.success=function(title,message){var defered,el;return el=angular.element(".lightbox-generic-success"),title&&el.find("h2.title").html(title),message&&el.find("p.message").html(message),defered=this.q.defer(),el.on("click.confirm-dialog","a.button-green",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),el.on("click.confirm-dialog","a.close",function(_this){return function(event){return event.preventDefault(),defered.resolve(),_this.hide(el)}}(this)),this.lightboxService.open(el),defered.promise},ConfirmService.prototype.loader=function(title,message){var el;return el=angular.element(".lightbox-generic-loading"),title&&el.find("h2.title").html(title),message&&el.find("p.message").html(message),{start:function(_this){return function(){return _this.lightboxService.open(el)}}(this),stop:function(_this){return function(){return _this.lightboxService.close(el)}}(this),update:function(){return function(status,title,message,percent){return title&&el.find("h2.title").html(title),message&&el.find("p.message").html(message),percent?(el.find(".spin").addClass("hidden"),el.find(".progress-bar-wrapper").removeClass("hidden"),el.find(".progress-bar-wrapper > .bar").width(percent+"%"),el.find(".progress-bar-wrapper > span").html(percent+"%").css("left",percent-9+"%")):(el.find(".spin").removeClass("hidden"),el.find(".progress-bar-wrapper").addClass("hidden"))}}(this)}},ConfirmService.prototype.notify=function(type,message,title,time){var body,el,selector;return selector=".notification-message-"+type,el=angular.element(selector),el.hasClass("active")?void 0:(el.find("h4").html(title?title:NOTIFICATION_MSG[type].title),el.find("p").html(message?message:NOTIFICATION_MSG[type].message),body=angular.element("body"),body.find(".notification-message .notification-light").removeClass("active").addClass("inactive"),body.find(selector).removeClass("inactive").addClass("active"),this.tsem&&cancelTimeout(this.tsem),time||(time="error"===type||"light-error"===type?3500:1500),this.tsem=timeout(time,function(_this){return function(){return body.find(selector).removeClass("active").addClass("inactive"),delete _this.tsem}}(this)),el.on("click",".icon-delete",function(){return function(){return body.find(selector).removeClass("active").addClass("inactive")}}(this)))},ConfirmService}(taiga.Service),module=angular.module("taigaCommon"),module.service("$tgConfirm",ConfirmService)}.call(this),function(){var LbUsEstimationDirective,UsEstimationDirective,module,taiga;taiga=this.taiga,module=angular.module("taigaCommon"),LbUsEstimationDirective=function($rootScope,$repo,$confirm,$template){var link,mainTemplate,pointsTemplate;return mainTemplate=$template.get("common/estimation/lb-us-estimation-points-per-role.html",!0),pointsTemplate=$template.get("common/estimation/lb-us-estimation-points.html",!0),link=function($scope,$el,$attrs,$model){var calculateTotalPoints,render,renderPoints;return render=function(points){var computableRoles,ctx,html,roles,totalPoints;return totalPoints=calculateTotalPoints(points)||0,computableRoles=_.filter($scope.project.roles,"computable"),roles=_.map(computableRoles,function(role){var pointId,pointObj;return pointId=points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj&&null!=pointObj.name?pointObj.name:"?",role}),ctx={totalPoints:totalPoints,roles:roles},html=mainTemplate(ctx),$el.html(html)},renderPoints=function(target,usPoints,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=usPoints[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points,roleId:roleId}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").remove(),$el.find(target).append(html),$el.find(".pop-points-open").popover().open(function(){return $(this).removeClass("active")}),$el.find(".pop-points-open").show()},calculateTotalPoints=function(points){var values;return values=_.map(points,function(v){var _ref;return(null!=(_ref=$scope.pointsById[v])?_ref.value:void 0)||0}),0===values.length?"0":_.reduce(values,function(acc,num){return acc+num})},$el.on("click",".total.clickable",function(event){var points,roleId,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),roleId=target.data("role-id"),points=$model.$modelValue,renderPoints(target,points,roleId),target.siblings().removeClass("active"),target.addClass("active")}),$el.on("click",".point",function(event){var pointId,points,roleId,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),roleId=target.data("role-id"),pointId=target.data("point-id"),$el.find(".popover").popover().close(),points=_.clone($model.$modelValue,!0),points[roleId]=pointId,$scope.$apply(function(){return $model.$setViewValue(points)})}),$scope.$watch($attrs.ngModel,function(points){return points?render(points):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgLbUsEstimation",["$rootScope","$tgRepo","$tgConfirm","$tgTemplate",LbUsEstimationDirective]),UsEstimationDirective=function($rootScope,$repo,$confirm,$qqueue,$template){var link,mainTemplate,pointsTemplate;return mainTemplate=$template.get("common/estimation/us-estimation-points-per-role.html",!0),pointsTemplate=$template.get("common/estimation/us-estimation-points.html",!0),link=function($scope,$el,$attrs,$model){var calculateTotalPoints,isEditable,render,renderPoints,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var computableRoles,ctx,html,roles,totalPoints;return totalPoints=null!=us.total_points?us.total_points:"?",computableRoles=_.filter($scope.project.roles,"computable"),roles=_.map(computableRoles,function(role){var pointId,pointObj;return pointId=us.points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj&&null!=pointObj.name?pointObj.name:"?",role}),ctx={totalPoints:totalPoints,roles:roles,editable:isEditable()},html=mainTemplate(ctx),$el.html(html)},renderPoints=function(target,us,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=us.points[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points,roleId:roleId}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").remove(),$el.find(target).append(html),$el.find(".pop-points-open").popover().open(function(){return $(this).removeClass("active").closest("li").removeClass("active")}),$el.find(".pop-points-open").show()},calculateTotalPoints=function(us){var notNullValues,values;return values=_.map(us.points,function(v){var _ref;return null!=(_ref=$scope.pointsById[v])?_ref.value:void 0}),0===values.length?"0":(notNullValues=_.filter(values,function(v){return null!=v}),0===notNullValues.length?"?":_.reduce(notNullValues,function(acc,num){return acc+num}))},save=$qqueue.bindAdd(function(){return function(roleId,pointId){var onError,onSuccess,points,us;return $el.find(".popover").popover().close(),us=angular.copy($model.$modelValue),points=_.clone($model.$modelValue.points,!0),points[roleId]=pointId,us.setAttr("points",points),us.points=points,us.total_points=calculateTotalPoints(us),$model.$setViewValue(us),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),us.revert(),$model.$setViewValue(us)},$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".total.clickable",function(event){var roleId,target,us;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),roleId=target.data("role-id"),us=$model.$modelValue,renderPoints(target,us,roleId),target.siblings().removeClass("active"),target.addClass("active")):void 0}),$el.on("click",".point",function(event){var pointId,roleId,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),roleId=target.data("role-id"),pointId=target.data("point-id"),save(roleId,pointId)):void 0}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsEstimation",["$rootScope","$tgRepo","$tgConfirm","$tgQqueue","$tgTemplate",UsEstimationDirective])}.call(this),function(){var defaultFilter,module,momentFormat,momentFromNow,taiga,unslugify,yesNoFilter;taiga=this.taiga,module=angular.module("taigaCommon"),defaultFilter=function(){return function(value,defaultValue){return value===[null,void 0]?defaultValue:value}},module.filter("default",defaultFilter),yesNoFilter=function(){return function(value){return value?"Yes":"No"}},module.filter("yesNo",yesNoFilter),unslugify=function(){return taiga.unslugify},module.filter("unslugify",unslugify),momentFormat=function(){return function(input,format){return input?moment(input).format(format):""}},module.filter("momentFormat",momentFormat),momentFromNow=function(){return function(input,without_suffix){return input?moment(input).fromNow(without_suffix||!1):""}},module.filter("momentFromNow",momentFromNow)}.call(this),function(){var HistoryController,HistoryDirective,bindOnce,debounce,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaCommon"),HistoryController=function(_super){function HistoryController(scope,repo,rs){this.scope=scope,this.repo=repo,this.rs=rs}return __extends(HistoryController,_super),HistoryController.$inject=["$scope","$tgRepo","$tgResources"],HistoryController.prototype.initialize=function(type,objectId){return this.type=type,this.objectId=objectId},HistoryController.prototype.loadHistory=function(type,objectId){return this.rs.history.get(type,objectId).then(function(_this){return function(history){var historyResult,_i,_len;for(_i=0,_len=history.length;_len>_i;_i++)historyResult=history[_i],null!=historyResult.values_diff.description_diff&&(historyResult.values_diff.description=historyResult.values_diff.description_diff),delete historyResult.values_diff.description_html,delete historyResult.values_diff.description_diff;return _this.scope.history=history,_this.scope.comments=_.filter(history,function(item){return""!==item.comment})}}(this))},HistoryController.prototype.deleteComment=function(type,objectId,activityId){return this.rs.history.deleteComment(type,objectId,activityId).then(function(_this){return function(){return _this.loadHistory(type,objectId)}}(this))},HistoryController.prototype.undeleteComment=function(type,objectId,activityId){return this.rs.history.undeleteComment(type,objectId,activityId).then(function(_this){return function(){return _this.loadHistory(type,objectId)}}(this))},HistoryController}(taiga.Controller),HistoryDirective=function($log,$loading,$qqueue,$template){var link,templateActivity,templateBase,templateBaseEntries,templateChangeAttachment,templateChangeDiff,templateChangeGeneric,templateChangePoints,templateDeletedComment,templateFn;return templateChangeDiff=$template.get("common/history/history-change-diff.html",!0),templateChangePoints=$template.get("common/history/history-change-points.html",!0),templateChangeGeneric=$template.get("common/history/history-change-generic.html",!0),templateChangeAttachment=$template.get("common/history/history-change-attachment.html",!0),templateDeletedComment=$template.get("common/history/history-deleted-comment.html",!0),templateActivity=$template.get("common/history/history-activity.html",!0),templateBaseEntries=$template.get("common/history/history-base-entries.html",!0),templateBase=$template.get("common/history/history-base.html",!0),link=function($scope,$el,$attrs,$ctrl){var countChanges,formatChange,getHumanizedFieldName,getUserAvatar,getUserFullName,objectId,renderActivity,renderAttachmentEntry,renderChange,renderChangeEntries,renderChangeEntry,renderChangesHelperText,renderComment,renderComments,renderHistory,save,showAllActivity,showAllComments,type;return type=$attrs.type,objectId=null,showAllComments=!1,showAllActivity=!1,bindOnce($scope,$attrs.ngModel,function(model){return type=$attrs.type,objectId=model.id,$ctrl.initialize(type,objectId),$ctrl.loadHistory(type,objectId)}),getHumanizedFieldName=function(field){var humanizedFieldNames;return humanizedFieldNames={assigned_to:"assigned to",is_closed:"is closed",finish_date:"finish date",client_requirement:"client requirement",team_requirement:"team requirement",milestone:"sprint",user_story:"user story",is_iocaine:"is iocaine",is_deprecated:"is deprecated"},humanizedFieldNames[field]||field},getUserFullName=function(userId){var _ref;return null!=(_ref=$scope.usersById[userId])?_ref.full_name_display:void 0},getUserAvatar=function(userId){return null!=$scope.usersById[userId]?$scope.usersById[userId].photo:"/images/unnamed.png"},countChanges=function(comment){return _.keys(comment.values_diff).length},formatChange=function(change){return _.isArray(change)?0===change.length?"nil":change.join(", "):""===change?"nil":change===!0?"yes":change===!1?"no":change},renderAttachmentEntry=function(value){var attachments;return attachments=_.map(value,function(changes,type){return"new"===type?_.map(changes,function(change){return templateChangeDiff({name:"new attachment",diff:change.filename})}):"deleted"===type?_.map(changes,function(change){return templateChangeDiff({name:"deleted attachment",diff:change.filename})}):_.map(changes,function(change){var diff,name;return name="updated attachment "+change.filename,diff=_.map(change.changes,function(values,name){return{name:getHumanizedFieldName(name),from:formatChange(values[0]),to:formatChange(values[1])}}),templateChangeAttachment({name:name,diff:diff})})}),_.flatten(attachments).join("\n")},renderChangeEntry=function(field,value){var from,name,to;return"description"===field?templateChangeDiff({name:"description",diff:value[1]}):"points"===field?templateChangePoints({points:value}):"attachments"===field?renderAttachmentEntry(value):"assigned_to"===field?(name=getHumanizedFieldName(field),from=formatChange(value[0]||"Unassigned"),to=formatChange(value[1]||"Unassigned"),templateChangeGeneric({name:name,from:from,to:to})):(name=getHumanizedFieldName(field),from=formatChange(value[0]),to=formatChange(value[1]),templateChangeGeneric({name:name,from:from,to:to}))},renderChangeEntries=function(change,join){var entries;return null==join&&(join=!0),entries=_.map(change.values_diff,function(value,field){return renderChangeEntry(field,value)}),join?entries.join("\n"):entries},renderChangesHelperText=function(change){var size;return size=countChanges(change),1===size?"Made "+size+" change":"Made "+size+" changes"},renderComment=function(comment){var _ref;return comment.delete_comment_date||comment.delete_comment_user?templateDeletedComment({deleteCommentDate:moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm"),deleteCommentUser:comment.delete_comment_user.name,deleteComment:comment.comment_html,activityId:comment.id,canRestoreComment:comment.delete_comment_user.pk===$scope.user.id||$scope.project.my_permissions.indexOf("modify_project")>-1}):templateActivity({avatar:getUserAvatar(comment.user.pk),userFullName:comment.user.name,creationDate:moment(comment.created_at).format("DD MMM YYYY HH:mm"),comment:comment.comment_html,changesText:renderChangesHelperText(comment),changes:renderChangeEntries(comment,!1),mode:"comment",deleteCommentDate:comment.delete_comment_date?moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm"):void 0,deleteCommentUser:(null!=(_ref=comment.delete_comment_user)?_ref.name:void 0)?comment.delete_comment_user.name:void 0,activityId:comment.id,canDeleteComment:comment.user.pk===$scope.user.id||$scope.project.my_permissions.indexOf("modify_project")>-1})},renderChange=function(change){var _ref;return templateActivity({avatar:getUserAvatar(change.user.pk),userFullName:change.user.name,creationDate:moment(change.created_at).format("DD MMM YYYY HH:mm"),comment:change.comment_html,changes:renderChangeEntries(change,!1),changesText:"",mode:"activity",deleteCommentDate:change.delete_comment_date?moment(change.delete_comment_date).format("DD MMM YYYY HH:mm"):void 0,deleteCommentUser:(null!=(_ref=change.delete_comment_user)?_ref.name:void 0)?change.delete_comment_user.name:void 0,activityId:change.id})},renderHistory=function(entries,totalEntries){var showMore;return showMore=entries.length===totalEntries?0:totalEntries-entries.length,templateBaseEntries({entries:entries,showMore:showMore})},renderComments=function(){var comments,html,totalComments;return comments=$scope.comments||[],totalComments=comments.length,showAllComments||(comments=_.last(comments,4)),comments=_.map(comments,function(x){return renderComment(x)}),html=renderHistory(comments,totalComments),$el.find(".comments-list").html(html)},renderActivity=function(){var changes,html,totalChanges;return changes=$scope.history||[],totalChanges=changes.length,showAllActivity||(changes=_.last(changes,4)),changes=_.map(changes,function(x){return renderChange(x)}),html=renderHistory(changes,totalChanges),$el.find(".changes-list").html(html)},save=$qqueue.bindAdd(function(){return function(target){var model,onError,onSuccess;return $scope.$broadcast("markdown-editor:submit"),$el.find(".comment-list").addClass("activeanimation"),onSuccess=function(){return $ctrl.loadHistory(type,objectId)["finally"](function(){return $loading.finish(target)})},onError=function(){return $loading.finish(target),$confirm.notify("error")},model=$scope.$eval($attrs.ngModel),$loading.start(target),$ctrl.repo.save(model).then(onSuccess,onError)}}(this)),$scope.$watch("comments",renderComments),$scope.$watch("history",renderActivity),$scope.$on("history:reload",function(){return $ctrl.loadHistory(type,objectId)}),$el.on("click",".add-comment a.button-green",debounce(2e3,function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),save(target)})),$el.on("click",".show-more",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parent().is(".changes-list")?(showAllActivity=!showAllActivity,renderActivity()):(showAllComments=!showAllComments,renderComments())}),$el.on("click",".show-deleted-comment",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parents(".activity-single").find(".hide-deleted-comment").show(),target.parents(".activity-single").find(".show-deleted-comment").hide(),target.parents(".activity-single").find(".comment-body").show()}),$el.on("click",".hide-deleted-comment",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parents(".activity-single").find(".hide-deleted-comment").hide(),target.parents(".activity-single").find(".show-deleted-comment").show(),target.parents(".activity-single").find(".comment-body").hide()}),$el.on("click",".changes-title",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.parent().find(".change-entry").toggleClass("active")}),$el.on("focus",".add-comment textarea",function(){return $(this).addClass("active")}),$el.on("click",".history-tabs li a",function(){return $el.find(".history-tabs li a").toggleClass("active"),$el.find(".history section").toggleClass("hidden")}),$el.on("click",".comment-delete",debounce(2e3,function(event){var activityId,target;return target=angular.element(event.currentTarget),activityId=target.data("activity-id"),$ctrl.deleteComment(type,objectId,activityId)})),$el.on("click",".comment-restore",debounce(2e3,function(event){var activityId,target;return target=angular.element(event.currentTarget),activityId=target.data("activity-id"),$ctrl.undeleteComment(type,objectId,activityId)})),$scope.$on("$destroy",function(){return $el.off()})},templateFn=function($el,$attrs){return templateBase({ngmodel:$attrs.ngModel,type:$attrs.type,mode:$attrs.mode}) +},{controller:HistoryController,template:templateFn,restrict:"AE",link:link}},module.directive("tgHistory",["$log","$tgLoading","$tgQqueue","$tgTemplate",HistoryDirective])}.call(this),function(){var ImportProjectButtonDirective,module;module=angular.module("taigaCommon"),ImportProjectButtonDirective=function($rs,$confirm,$location,$navUrls){var link;return link=function($scope,$el){return $el.on("click",".import-project-button",function(event){return event.preventDefault(),$el.find("input.import-file").val(""),$el.find("input.import-file").trigger("click")}),$el.on("change","input.import-file",function(event){var file,loader,onError,onSuccess;return event.preventDefault(),(file=event.target.files[0])?(loader=$confirm.loader("Uploading dump file"),onSuccess=function(result){var ctx,message,title;return loader.stop(),202===result.status?(title="Our Oompa Loompas are importing your project",message="This process could take a few minutes
    We will send you an email when ready",$confirm.success(title,message)):(ctx={project:result.data.slug},$location.path($navUrls.resolve("project-admin-project-profile-details",ctx)),$confirm.notify("success","Your project has been imported successfuly."))},onError=function(result){var errorMsg,_ref;return loader.stop(),console.log("Error",result),errorMsg="Our oompa loompas have some problems importing your dump data. Please try again. ",429===result.status?errorMsg="Sorry, our oompa loompas are very busy right now. Please try again in a few minutes. ":(null!=(_ref=result.data)?_ref._error_message:void 0)&&(errorMsg="Our oompa loompas have some problems importing your dump data: "+result.data._error_message),$confirm.notify("error",errorMsg)},loader.start(),$rs.projects["import"](file,loader.update).then(onSuccess,onError)):void 0})},{link:link}},module.directive("tgImportProjectButton",["$tgResources","$tgConfirm","$location","$tgNavUrls",ImportProjectButtonDirective])}.call(this),function(){var AssignedToLightboxDirective,BlockLightboxDirective,BlockingMessageInputDirective,CreateBulkUserstoriesDirective,CreateEditUserstoryDirective,LightboxDirective,LightboxKeyboardNavigationService,LightboxService,NotionButtonDirective,NotionLightboxDirective,WatchersLightboxDirective,bindOnce,debounce,module,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};module=angular.module("taigaCommon"),bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,debounce=this.taiga.debounce,LightboxService=function(_super){function LightboxService(animationFrame){this.animationFrame=animationFrame}return __extends(LightboxService,_super),LightboxService.prototype.open=function($el){var docEl,lightboxContent;return lightboxContent=$el.children().not(".close"),lightboxContent.hide(),$el.css("display","flex"),$el.find("input,textarea").first().focus(),this.animationFrame.add(function(){return function(){return $el.addClass("open"),lightboxContent.show()}}(this)),docEl=angular.element(document),docEl.on("keydown.lightbox",function(_this){return function(e){var code;return code=e.keyCode?e.keyCode:e.which,27===code?_this.close($el):void 0}}(this))},LightboxService.prototype.close=function($el){var docEl;return docEl=angular.element(document),docEl.off(".lightbox"),docEl.off(".keyboard-navigation"),$el.one("transitionend",function(){return function(){return $el.removeAttr("style"),$el.removeClass("open").removeClass("close")}}(this)),$el.addClass("close")},LightboxService.prototype.closeAll=function(){var docEl,lightboxEl,_i,_len,_ref,_results;for(docEl=angular.element(document),_ref=docEl.find(".lightbox.open"),_results=[],_i=0,_len=_ref.length;_len>_i;_i++)lightboxEl=_ref[_i],_results.push(this.close($(lightboxEl)));return _results},LightboxService}(taiga.Service),module.service("lightboxService",["animationFrame",LightboxService]),LightboxKeyboardNavigationService=function(_super){function LightboxKeyboardNavigationService(){return LightboxKeyboardNavigationService.__super__.constructor.apply(this,arguments)}return __extends(LightboxKeyboardNavigationService,_super),LightboxKeyboardNavigationService.prototype.stop=function(){var docEl;return docEl=angular.element(document),docEl.off(".keyboard-navigation")},LightboxKeyboardNavigationService.prototype.dispatch=function($el,code){var activeElement,next,prev;if(activeElement=$el.find(".active"),13===code)return activeElement.trigger("click");if(40===code){if(!activeElement.length)return $el.find(".watcher-single:first").addClass("active");if(next=activeElement.next(".watcher-single"),next.length)return activeElement.removeClass("active"),next.addClass("active")}else if(38===code){if(!activeElement.length)return $el.find(".watcher-single:last").addClass("active");if(prev=activeElement.prev(".watcher-single"),prev.length)return activeElement.removeClass("active"),prev.addClass("active")}},LightboxKeyboardNavigationService.prototype.init=function($el){var docEl;return this.stop(),docEl=angular.element(document),docEl.on("keydown.keyboard-navigation",function(_this){return function(event){var code;return code=event.keyCode?event.keyCode:event.which,40===code||38===code||13===code?(event.preventDefault(),_this.dispatch($el,code)):void 0}}(this))},LightboxKeyboardNavigationService}(taiga.Service),module.service("lightboxKeyboardNavigationService",LightboxKeyboardNavigationService),LightboxDirective=function(lightboxService){var link;return link=function($scope,$el){return $el.on("click",".close",function(event){return event.preventDefault(),lightboxService.close($el)})},{restrict:"C",link:link}},module.directive("lightbox",["lightboxService",LightboxDirective]),BlockLightboxDirective=function($rootscope,$tgrepo,$confirm,lightboxService,$loading,$qqueue){var link;return link=function($scope,$el,$attrs,$model){var block,unblock;return $el.find("h2.title").text($attrs.title),unblock=$qqueue.bindAdd(function(){return function(item,finishCallback){var promise;return promise=$tgrepo.save(item),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload"),$model.$setViewValue(item),finishCallback()}),promise.then(null,function(){return $confirm.notify("error"),item.revert(),$model.$setViewValue(item)}),promise["finally"](function(){return finishCallback()}),promise}}(this)),block=$qqueue.bindAdd(function(){return function(item){var promise;return $model.$setViewValue(item),$loading.start($el.find(".button-green")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $confirm.notify("error"),item.revert(),$model.$setViewValue(item)}),promise["finally"](function(){return $loading.finish($el.find(".button-green")),lightboxService.close($el)})}}(this)),$scope.$on("block",function(){return $el.find(".reason").val($model.$modelValue.blocked_note),lightboxService.open($el)}),$scope.$on("unblock",function(){return function(event,model,finishCallback){var item;return item=$model.$modelValue.clone(),item.is_blocked=!1,item.blocked_note="",unblock(item,finishCallback)}}(this)),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click",".button-green",function(event){var item;return event.preventDefault(),item=$model.$modelValue.clone(),item.is_blocked=!0,item.blocked_note=$el.find(".reason").val(),block(item)})},{templateUrl:"common/lightbox/lightbox-block.html",link:link,require:"ngModel"}},module.directive("tgLbBlock",["$rootScope","$tgRepo","$tgConfirm","lightboxService","$tgLoading","$tgQqueue",BlockLightboxDirective]),BlockingMessageInputDirective=function($log,$template){var link,template,templateFn;return template=$template.get("common/lightbox/lightbox-blocking-message-input.html",!0),link=function($scope,$el,$attrs){return $attrs.watch?$scope.$watch($attrs.watch,function(value){return value===!0&&value===!0?$el.find(".blocked-note").removeClass("hidden"):$el.find(".blocked-note").addClass("hidden")}):$log.error("No watch attribute on tg-blocking-message-input directive")},templateFn=function($el,$attrs){return template({ngmodel:$attrs.ngModel})},{template:templateFn,link:link,require:"ngModel",restrict:"EA"}},module.directive("tgBlockingMessageInput",["$log","$tgTemplate",BlockingMessageInputDirective]),CreateEditUserstoryDirective=function($repo,$model,$rs,$rootScope,lightboxService,$loading){var link;return link=function($scope,$el){var submit,submitButton;return $scope.isNew=!0,$scope.$on("usform:new",function(ctx,projectId,status,statusList){return $scope.isNew=!0,$scope.usStatusList=statusList,$scope.us=$model.make_model("userstories",{project:projectId,points:{},status:status,is_archived:!1,tags:[]}),$el.find(".button-green").html("Create"),$el.find(".title").html("New user story "),$el.find(".tag-input").val(""),$el.find(".blocked-note").addClass("hidden"),$el.find("label.blocked").removeClass("selected"),$el.find("label.team-requirement").removeClass("selected"),$el.find("label.client-requirement").removeClass("selected"),lightboxService.open($el)}),$scope.$on("usform:edit",function(ctx,us){return $scope.us=us,$scope.isNew=!1,$el.find(".button-green").html("Save"),$el.find(".title").html("Edit user story "),$el.find(".tag-input").val(""),us.is_blocked?($el.find(".blocked-note").removeClass("hidden"),$el.find("label.blocked").addClass("selected")):($el.find(".blocked-note").addClass("hidden"),$el.find("label.blocked").removeClass("selected")),us.team_requirement?$el.find("label.team-requirement").addClass("selected"):$el.find("label.team-requirement").removeClass("selected"),us.client_requirement?$el.find("label.client-requirement").addClass("selected"):$el.find("label.client-requirement").removeClass("selected"),lightboxService.open($el)}),submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),$scope.isNew?(promise=$repo.create("userstories",$scope.us),broadcastEvent="usform:new:success"):(promise=$repo.save($scope.us),broadcastEvent="usform:edit:success"),promise.then(function(data){return $loading.finish(submitButton),lightboxService.close($el),$rootScope.$broadcast(broadcastEvent,data)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".close",function(event){return event.preventDefault(),$scope.$apply(function(){return $scope.us.revert()}),lightboxService.close($el)}),$el.keydown(function(event){var code;return code=event.keyCode?event.keyCode:event.which,27===code?(lightboxService.close($el),$scope.$apply(function(){return $scope.us.revert()})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateEditUserstory",["$tgRepo","$tgModel","$tgResources","$rootScope","lightboxService","$tgLoading",CreateEditUserstoryDirective]),CreateBulkUserstoriesDirective=function($repo,$rs,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var submit,submitButton;return $scope.$on("usform:bulk",function(ctx,projectId,status){return $scope["new"]={projectId:projectId,statusId:status,bulk:""},lightboxService.open($el)}),submit=debounce(2e3,function(){return function(event){var form,promise;return event.preventDefault(),form=$el.find("form").checksley({onlyOneErrorElement:!0}),form.validate()?($loading.start(submitButton),promise=$rs.userstories.bulkCreate($scope["new"].projectId,$scope["new"].statusId,$scope["new"].bulk),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("usform:bulk:success",result),lightboxService.close($el)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateBulkUserstories",["$tgRepo","$tgResources","$rootScope","lightboxService","$tgLoading",CreateBulkUserstoriesDirective]),AssignedToLightboxDirective=function(lightboxService,lightboxKeyboardNavigationService,$template){var link;return link=function($scope,$el){var closeLightbox,filterUsers,normalizeString,render,selectedItem,selectedUser,usersTemplate;return selectedUser=null,selectedItem=null,usersTemplate=$template.get("common/lightbox/lightbox-assigned-to-users.html",!0),normalizeString=function(string){var normalizedString;return normalizedString=string,normalizedString=normalizedString.replace("Á","A").replace("Ä","A").replace("À","A"),normalizedString=normalizedString.replace("É","E").replace("Ë","E").replace("È","E"),normalizedString=normalizedString.replace("Í","I").replace("Ï","I").replace("Ì","I"),normalizedString=normalizedString.replace("Ó","O").replace("Ö","O").replace("Ò","O"),normalizedString=normalizedString.replace("Ú","U").replace("Ü","U").replace("Ù","U")},filterUsers=function(text,user){var username;return username=user.full_name_display.toUpperCase(),username=normalizeString(username),text=text.toUpperCase(),text=normalizeString(text),_.contains(username,text)},render=function(selected,text){var ctx,html,users;return $el.find("input").focus(),users=_.clone($scope.activeUsers,!0),null!=selected&&(users=_.reject(users,{id:selected.id})),null!=text&&(users=_.filter(users,_.partial(filterUsers,text))),ctx={selected:selected,users:_.first(users,5),showMore:users.length>5},html=usersTemplate(ctx),$el.find("div.watchers").html(html),lightboxKeyboardNavigationService.init($el)},closeLightbox=function(){return lightboxKeyboardNavigationService.stop(),lightboxService.close($el)},$scope.$on("assigned-to:add",function(ctx,item){var assignedToId;return selectedItem=item,assignedToId=item.assigned_to,selectedUser=$scope.usersById[assignedToId],render(selectedUser),lightboxService.open($el),$el.find("input").focus()}),$scope.$watch("usersSearch",function(searchingText){return null!=searchingText?render(selectedUser,searchingText):void 0}),$el.on("click",".watcher-single",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),closeLightbox(),$scope.$apply(function(){return $scope.$broadcast("assigned-to:added",target.data("user-id"),selectedItem),$scope.usersSearch=null})}),$el.on("click",".remove-assigned-to",function(event){return event.preventDefault(),event.stopPropagation(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null,$scope.$broadcast("assigned-to:added",null,selectedItem)})}),$el.on("click",".close",function(event){return event.preventDefault(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"common/lightbox/lightbox-assigned-to.html",link:link}},module.directive("tgLbAssignedto",["lightboxService","lightboxKeyboardNavigationService","$tgTemplate",AssignedToLightboxDirective]),WatchersLightboxDirective=function($repo,lightboxService,lightboxKeyboardNavigationService){var link;return link=function($scope,$el){var closeLightbox,getFilteredUsers,render,selectedItem;return selectedItem=null,getFilteredUsers=function(text){var users,_filterUsers;return null==text&&(text=""),_filterUsers=function(text,user){var username;return selectedItem&&_.find(selectedItem.watchers,function(x){return x===user.id})?!1:(username=user.full_name_display.toUpperCase(),text=text.toUpperCase(),_.contains(username,text))},users=_.clone($scope.activeUsers,!0),users=_.filter(users,_.partial(_filterUsers,text))},render=function(users){var ctx,html;return $el.find("input").focus(),ctx={selected:!1,users:_.first(users,5),showMore:users.length>5},html=usersTemplate(ctx),$el.find("div.watchers").html(html)},closeLightbox=function(){return lightboxKeyboardNavigationService.stop(),lightboxService.close($el)},$scope.$on("watcher:add",function(ctx,item){var users;return selectedItem=item,users=getFilteredUsers(),render(users),lightboxService.open($el),lightboxKeyboardNavigationService.init($el)}),$scope.$watch("usersSearch",function(searchingText){var users;if(null!=searchingText)return users=getFilteredUsers(searchingText),render(users)}),$el.on("click",".watcher-single",debounce(2e3,function(event){var target;return closeLightbox(),event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $scope.usersSearch=null,$scope.$broadcast("watcher:added",target.data("user-id"))})})),$el.on("click",".close",function(event){return event.preventDefault(),closeLightbox(),$scope.$apply(function(){return $scope.usersSearch=null})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"common/lightbox/lightbox-users.html",link:link}},module.directive("tgLbWatchers",["$tgRepo","lightboxService","lightboxKeyboardNavigationService",WatchersLightboxDirective]),NotionLightboxDirective=function(lightboxService){var link;return link=function($scope,$el){return $scope.$on("notion:open",function(event,lightboxId){return $el.attr("id")===lightboxId?lightboxService.open($el):void 0}),$el.on("click",".button-green",function(){return lightboxService.close($el)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbNotion",["lightboxService",NotionLightboxDirective]),NotionButtonDirective=function($log,$rootScope){var link;return link=function($scope,$el,$attrs){return null==$attrs.tgLbNotionButton?$log.error("NotionButtonDirective: the directive need the id of the notion lightbox"):($el.on("click",function(){return $rootScope.$broadcast("notion:open",$attrs.tgLbNotionButton)}),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgLbNotionButton",["$log","$rootScope",NotionButtonDirective])}.call(this),function(){var Loader,LoaderDirective,module,sizeFormat,taiga,timeout;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,timeout=this.taiga.timeout,module=angular.module("taigaCommon"),LoaderDirective=function(tgLoader,$rootscope){var link;return link=function($scope,$el){return tgLoader.onStart(function(){return $(document.body).addClass("loader-active"),$el.addClass("active")}),tgLoader.onEnd(function(){return $(document.body).removeClass("loader-active"),$el.removeClass("active")}),$rootscope.$on("$routeChangeSuccess",function(){return tgLoader.startCurrentPageLoader()}),$rootscope.$on("$locationChangeSuccess",function(){return tgLoader.reset()})},{link:link}},module.directive("tgLoader",["tgLoader","$rootScope",LoaderDirective]),Loader=function(){var config,defaultConfig,forceDisabled;forceDisabled=!1,defaultConfig={enabled:!1,minTime:300},config=_.merge({},defaultConfig),this.add=function(){return function(){return forceDisabled?void 0:config.enabled=!0}},this.$get=["$rootScope",function($rootscope){var pageLoaded,reset,start,startLoadTime;return startLoadTime=0,reset=function(){return config=_.merge({},defaultConfig)},pageLoaded=function(force){var diff,endTime,timeoutValue;return null==force&&(force=!1),startLoadTime?(timeoutValue=0,force||(endTime=(new Date).getTime(),diff=endTime-startLoadTime,diff"))},TgLoadingService.prototype.finish=function(target){var oldContent;return target.hasClass("loading")?(oldContent=target.data("loading-old-content"),target.data("loading-old-content",null),target.html(oldContent),target.removeClass("loading")):void 0},TgLoadingService}(taiga.Service),module.service("$tgLoading",TgLoadingService)}.call(this),function(){var RelatedTaskStatusDirective,UsStatusDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaCommon"),UsStatusDirective=function($repo,$template){var link,template;return template=$template.get("common/popover/popover-us-status.html",!0),link=function($scope,$el,$attrs){var $ctrl,render,us;return $ctrl=$el.controller(),render=function(us){var usStatusById,usStatusDom,usStatusDomParent;return usStatusDomParent=$el.find(".us-status"),usStatusDom=$el.find(".us-status .us-status-bind"),usStatusById=$scope.usStatusById,usStatusById[us.status]?(usStatusDom.text(usStatusById[us.status].name),usStatusDomParent.css("color",usStatusById[us.status].color)):void 0},$el.on("click",".us-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",debounce(2e3,function(event){var target,us;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),us=$scope.$eval($attrs.tgUsStatus),us.status=target.data("status-id"),render(us),$el.find(".pop-status").popover().close(),$scope.$apply(function(){return $repo.save(us).then(function(){return $scope.$eval($attrs.onUpdate)})})})),$scope.$on("userstories:loaded",function(){return render($scope.$eval($attrs.tgUsStatus))}),$scope.$on("$destroy",function(){return $el.off()}),us=$scope.$eval($attrs.tgUsStatus),render(us),bindOnce($scope,"project",function(project){var html;return html=template({statuses:project.us_statuses}),$el.append(html),-1===$scope.project.my_permissions.indexOf("modify_us")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0})},{link:link}},module.directive("tgUsStatus",["$tgRepo","$tgTemplate",UsStatusDirective]),RelatedTaskStatusDirective=function($repo,$template){var link,selectionTemplate,updateTaskStatus;return selectionTemplate=$template.get("common/popover/popover-related-task-status.html",!0),updateTaskStatus=function($el,task,taskStatusById){var taskStatusDom,taskStatusDomParent;return taskStatusDomParent=$el.find(".us-status"),taskStatusDom=$el.find(".task-status .task-status-bind"),taskStatusById[task.status]?(taskStatusDom.text(taskStatusById[task.status].name),taskStatusDomParent.css("color",taskStatusById[task.status].color)):void 0},link=function($scope,$el,$attrs){var $ctrl,autoSave,notAutoSave,task;return $ctrl=$el.controller(),task=$scope.$eval($attrs.tgRelatedTaskStatus),notAutoSave=$scope.$eval($attrs.notAutoSave),autoSave=!notAutoSave,$el.on("click",".task-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",debounce(2e3,function(event){var target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),task.status=target.data("status-id"),$el.find(".pop-status").popover().close(),updateTaskStatus($el,task,$scope.taskStatusById),autoSave?$scope.$apply(function(){return $repo.save(task).then(function(){return $scope.$eval($attrs.onUpdate),$scope.$emit("related-tasks:status-changed")})}):void 0})),taiga.bindOnce($scope,"project",function(project){return $el.append(selectionTemplate({statuses:project.task_statuses})),updateTaskStatus($el,task,$scope.taskStatusById),-1===project.my_permissions.indexOf("modify_task")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRelatedTaskStatus",["$tgRepo","$tgTemplate",RelatedTaskStatusDirective]),$.fn.popover=function(){var $el,close,closeAll,closePopover,isVisible,open;return $el=this,isVisible=function(){return function(){var docViewBottom,docViewLeft,docViewRight,docViewTop,docViewWidth,elemBottom,elemLeft,elemRight,elemTop,elemWidth;return $el.css({display:"block",visibility:"hidden"}),docViewTop=$(window).scrollTop(),docViewBottom=docViewTop+$(window).height(),docViewWidth=$(window).width(),docViewRight=docViewWidth,docViewLeft=0,elemTop=$el.offset().top,elemBottom=elemTop+$el.height(),elemWidth=$el.width(),elemLeft=$el.offset().left,elemRight=$el.offset().left+elemWidth,$el.css({display:"none",visibility:"visible"}),docViewBottom>=elemBottom&&elemTop>=docViewTop&&elemLeft>=docViewLeft&&docViewRight>=elemRight}}(this),closePopover=function(){return function(onClose){return onClose&&onClose.call($el),$el.fadeOut(function(){return $el.removeClass("active").removeClass("fix")}),$el.off("popup:close")}}(this),closeAll=function(){return function(){return $(".popover.active").each(function(){return $(this).trigger("popup:close")})}}(this),open=function(){return function(onClose){return $el.hasClass("active")?close():(closeAll(),isVisible()||$el.addClass("fix"),$el.fadeIn(function(){return $el.addClass("active"),$(document.body).off("popover"),$(document.body).one("click.popover",function(){return closeAll()})}),$el.on("popup:close",function(){return closePopover(onClose)}))}}(this),close=function(){return function(){return $el.trigger("popup:close")}}(this),{open:open,close:close,closeAll:closeAll}}}.call(this),function(){var ExceptionHandlerFactory,module,taiga;taiga=this.taiga,module=angular.module("taigaCommon"),ExceptionHandlerFactory=function($log,config){var ravenConfig;return this.config=config,ravenConfig=this.config.get("ravenConfig",null),ravenConfig?($log.debug("Using the RavenJS exception handler."),Raven.config(ravenConfig).install(),function(exception){return $log.error.apply($log,arguments),Raven.captureException(exception)}):($log.debug("Using the default logging exception handler."),function(){return $log.error.apply($log,arguments)})},module.factory("$exceptionHandler",["$log","$tgConfig",ExceptionHandlerFactory])}.call(this),function(){var ColorizeTagsDirective,LbTagLineDirective,TagLineDirective,TagsDirective,bindOnce,module,taiga,trim,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),TagsDirective=function(){var formatter,link,parser;return formatter=function(v){return _.isArray(v)?v.join(", "):""},parser=function(v){var result;return v?(result=_(v.split(",")).map(function(x){return _.str.trim(x)}),result.value()):[]},link=function($scope,$el,$attrs,$ctrl){return $ctrl.$formatters.push(formatter),$ctrl.$parsers.push(parser),$scope.$on("$destroy",function(){return $el.off()})},{require:"ngModel",link:link}},module.directive("tgTags",TagsDirective),ColorizeTagsDirective=function(){var link,templates;return templates={backlog:_.template('<% _.each(tags, function(tag) { %>\n <%- tag.name %>\n<% }) %>'),kanban:_.template('<% _.each(tags, function(tag) { %>\n \n<% }) %>'),taskboard:_.template('<% _.each(tags, function(tag) { %>\n \n<% }) %>')},link=function($scope,$el,$attrs){var render;return render=function(srcTags){var html,tags,template;return template=templates[$attrs.tgColorizeTagsType],srcTags.sort(),tags=_.map(srcTags,function(tag){var color;return color=$scope.project.tags_colors[tag],{name:tag,color:color}}),html=template({tags:tags}),$el.html(html)},$scope.$watch($attrs.tgColorizeTags,function(tags){return null!=tags?render(tags):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgColorizeTags",ColorizeTagsDirective),LbTagLineDirective=function($rs,$template){var COMMA_KEY,ENTER_KEY,link,templateTags;return ENTER_KEY=13,COMMA_KEY=188,templateTags=$template.get("common/tag/lb-tag-line-tags.html",!0),link=function($scope,$el,$attrs,$model){var addValue,deleteValue,hideSaveButton,removeInputLastCharacter,renderTags,resetInput,saveInputTag,showSaveButton;return renderTags=function(tags,tagsColors){var ctx,html;return ctx={tags:_.map(tags,function(t){return{name:t,color:tagsColors[t]}})},_.map(ctx.tags,function(){return function(tag){return tag.color?tag.style="border-left: 5px solid "+tag.color:void 0}}(this)),html=templateTags(ctx),$el.find("div.tags-container").html(html)},showSaveButton=function(){return $el.find(".save").removeClass("hidden")},hideSaveButton=function(){return $el.find(".save").addClass("hidden")},resetInput=function(){return $el.find("input").val(""),$el.find("input").autocomplete("close")},addValue=function(value){var tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue,!1),null==tags&&(tags=[]),__indexOf.call(tags,value)<0&&tags.push(value),$scope.$apply(function(){return $model.$setViewValue(tags)})):void 0},deleteValue=function(value){var tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue,!1),tags=_.pull(tags,value),$scope.$apply(function(){return $model.$setViewValue(tags)})):void 0},saveInputTag=function(){var value;return value=$el.find("input").val(),addValue(value),resetInput(),hideSaveButton()},removeInputLastCharacter=function(){return function(input){var inputValue;return inputValue=input.val(),input.val(inputValue.substring(0,inputValue.length-1))}}(this),$el.on("keypress","input",function(event){return event.keyCode===ENTER_KEY?event.preventDefault():void 0}),$el.on("keyup","input",function(event){var target;return target=angular.element(event.currentTarget),event.keyCode===ENTER_KEY?saveInputTag():event.keyCode===COMMA_KEY?(removeInputLastCharacter(target),saveInputTag()):target.val().length?showSaveButton():hideSaveButton()}),$el.on("click",".save",function(event){return event.preventDefault(),saveInputTag()}),$el.on("click",".icon-delete",function(event){var target,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.siblings(".tag-name").text(),deleteValue(value)}),bindOnce($scope,"project",function(project){var positioningFunction;return positioningFunction=function(position,elements){var menu;return menu=elements.element.element,menu.css("width",elements.target.width),menu.css("top",position.top),menu.css("left",position.left)},$el.find("input").autocomplete({source:_.keys(project.tags_colors),position:{my:"left top",using:positioningFunction},select:function(event,ui){return addValue(ui.item.value),ui.item.value=""}})}),$scope.$watch($attrs.ngModel,function(tags){var tagsColors,_ref; +return tagsColors=(null!=(_ref=$scope.project)?_ref.tags_colors:void 0)||[],renderTags(tags,tagsColors)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel",templateUrl:"common/tag/lb-tag-line.html"}},module.directive("tgLbTagLine",["$tgResources","$tgTemplate",LbTagLineDirective]),TagLineDirective=function($rootScope,$repo,$rs,$confirm,$qqueue,$template){var COMMA_KEY,ENTER_KEY,ESC_KEY,link,templateTags;return ENTER_KEY=13,ESC_KEY=27,COMMA_KEY=188,templateTags=$template.get("common/tag/tags-line-tags.html",!0),link=function($scope,$el,$attrs,$model){var addValue,deleteValue,hideAddTagButton,hideAddTagButtonText,hideInput,hideSaveButton,isEditable,removeInputLastCharacter,renderInReadModeOnly,renderTags,resetInput,saveInputTag,showAddTagButton,showAddTagButtonText,showInput,showSaveButton;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf($attrs.requiredPerm)},renderTags=function(tags,tagsColors){var ctx,html;return ctx={tags:_.map(tags,function(t){return{name:t,color:tagsColors[t]}}),isEditable:isEditable()},html=templateTags(ctx),$el.find("div.tags-container").html(html)},renderInReadModeOnly=function(){return $el.find(".add-tag").remove(),$el.find("input").remove(),$el.find(".save").remove()},showAddTagButton=function(){return $el.find(".add-tag").removeClass("hidden")},hideAddTagButton=function(){return $el.find(".add-tag").addClass("hidden")},showAddTagButtonText=function(){return $el.find(".add-tag-text").removeClass("hidden")},hideAddTagButtonText=function(){return $el.find(".add-tag-text").addClass("hidden")},showSaveButton=function(){return $el.find(".save").removeClass("hidden")},hideSaveButton=function(){return $el.find(".save").addClass("hidden")},showInput=function(){return $el.find("input").removeClass("hidden").focus()},hideInput=function(){return $el.find("input").addClass("hidden").blur()},resetInput=function(){return $el.find("input").val(""),$el.find("input").autocomplete("close")},addValue=$qqueue.bindAdd(function(value){var model,onError,onSuccess,tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue.tags,!1),null==tags&&(tags=[]),__indexOf.call(tags,value)<0&&tags.push(value),model=$model.$modelValue.clone(),model.tags=tags,$model.$setViewValue(model),onSuccess=function(){return $rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),model.revert(),$model.$setViewValue(model)},$repo.save(model).then(onSuccess,onError)):void 0}),deleteValue=$qqueue.bindAdd(function(value){var model,onError,onSuccess,tags;return value=trim(value.toLowerCase()),0!==value.length?(tags=_.clone($model.$modelValue.tags,!1),tags=_.pull(tags,value),model=$model.$modelValue.clone(),model.tags=tags,$model.$setViewValue(model),onSuccess=function(){return $rootScope.$broadcast("history:reload")},onError=function(){return $confirm.notify("error"),model.revert(),$model.$setViewValue(model)},$repo.save(model).then(onSuccess,onError)):void 0}),saveInputTag=function(){var value;return value=$el.find("input").val(),addValue(value),resetInput(),hideSaveButton()},removeInputLastCharacter=function(){return function(input){var inputValue;return inputValue=input.val(),input.val(inputValue.substring(0,inputValue.length-1))}}(this),$el.on("keypress","input",function(event){var _ref;if((_ref=event.keyCode)===ENTER_KEY||_ref===ESC_KEY)return event.preventDefault()}),$el.on("keyup","input",function(event){var target;return target=angular.element(event.currentTarget),event.keyCode===ENTER_KEY?saveInputTag():event.keyCode===COMMA_KEY?(removeInputLastCharacter(target),saveInputTag()):event.keyCode===ESC_KEY?(resetInput(),hideInput(),hideSaveButton(),showAddTagButton()):target.val().length?showSaveButton():hideSaveButton()}),$el.on("click",".save",function(event){return event.preventDefault(),saveInputTag()}),$el.on("click",".add-tag",function(event){return event.preventDefault(),hideAddTagButton(),showInput()}),$el.on("click",".icon-delete",function(event){var target,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.siblings(".tag-name").text(),deleteValue(value)}),bindOnce($scope,"project",function(project){var positioningFunction;return isEditable()?(showAddTagButton(),positioningFunction=function(position,elements){var menu;return menu=elements.element.element,menu.css("width",elements.target.width),menu.css("top",position.top),menu.css("left",position.left)},$el.find("input").autocomplete({source:_.keys(project.tags_colors),position:{my:"left top",using:positioningFunction},select:function(event,ui){return addValue(ui.item.value),ui.item.value=""}})):void renderInReadModeOnly()}),$scope.$watch($attrs.ngModel,function(model){var tagsColors,_ref,_ref1;if(model)return(null!=(_ref=model.tags)?_ref.length:void 0)?hideAddTagButtonText():showAddTagButtonText(),tagsColors=(null!=(_ref1=$scope.project)?_ref1.tags_colors:void 0)||[],renderTags(model.tags,tagsColors)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel",templateUrl:"common/tag/tag-line.html"}},module.directive("tgTagLine",["$rootScope","$tgRepo","$tgResources","$tgConfirm","$tgQqueue","$tgTemplate",TagLineDirective])}.call(this),function(){var bindOnce,module,taiga,tgMarkitupDirective;taiga=this.taiga,bindOnce=this.taiga.bindOnce,module=angular.module("taigaCommon"),tgMarkitupDirective=function($rootscope,$rs,$tr,$selectedText,$template){var link,previewTemplate;return previewTemplate=$template.get("common/wysiwyg/wysiwyg-markitup-preview.html",!0),link=function($scope,$el,$attrs,$model){var closePreviewMode,element,markdownCaretPositon,markdownSettings,markdownTitle,preview,previewDomNode,removeEmptyLine,setCaretPosition;return element=angular.element($el),previewDomNode=$("
    ",{"class":"preview"}),closePreviewMode=function(){return element.parents(".markdown").find(".preview").remove(),element.parents(".markItUp").show()},$scope.$on("markdown-editor:submit",function(){return closePreviewMode()}),preview=function(){var markItUpDomNode,markdownDomNode;return markdownDomNode=element.parents(".markdown"),markItUpDomNode=element.parents(".markItUp"),$rs.mdrender.render($scope.projectId,$model.$modelValue).then(function(data){var markdown;return markdownDomNode.append(previewTemplate({data:data.data})),markItUpDomNode.hide(),markdown=element.closest(".markdown"),markdown.on("mouseup.preview",".preview",function(event){var target;return event.preventDefault(),target=angular.element(event.target),target.is("a")||!$selectedText.get().length?(markdown.off(".preview"),closePreviewMode()):void 0})})},markdownCaretPositon=!1,setCaretPosition=function(elm,caretPos){var range;return elm.createTextRange?(range=elm.createTextRange(),range.move("character",caretPos),range.select()):elm.selectionStart?(elm.focus(),elm.setSelectionRange(caretPos,caretPos)):void 0},removeEmptyLine=function(textarea,line,currentCaretPosition){var lines,removedLineLength;return lines=textarea.value.split("\n"),removedLineLength=lines[line].length,lines[line]="",textarea.value=lines.join("\n"),currentCaretPosition-removedLineLength+1},markdownSettings={nameSpace:"markdown",onShiftEnter:{keepDefault:!1,openWith:"\n\n"},onEnter:{keepDefault:!1,replaceWith:function(){return function(data){var breakLineAtBeginning,cursorLine,emptyListItem,lastLine,lines,match,newLineContent;if(lines=data.textarea.value.split("\n"),cursorLine=data.textarea.value.slice(0,+(data.caretPosition-1)+1||9e9).split("\n").length,newLineContent=data.textarea.value.slice(data.caretPosition).split("\n")[0],lastLine=lines[cursorLine-1],match=lastLine.match(/^(\s*- ).*/))if(emptyListItem=lastLine.match(/^(\s*)\-\s$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)\-\s/),!breakLineAtBeginning&&match)return"\n"+match[1];if(match=lastLine.match(/^(\s*\* ).*/))if(emptyListItem=lastLine.match(/^(\s*\* )$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)\*\s/),!breakLineAtBeginning&&match)return"\n"+match[1];if(match=lastLine.match(/^(\s*)(\d+)\.\s/))if(emptyListItem=lastLine.match(/^(\s*)(\d+)\.\s$/))markdownCaretPositon=removeEmptyLine(data.textarea,lines.length-1,data.caretPosition);else if(breakLineAtBeginning=newLineContent.match(/^(\s*)(\d+)\.\s/),!breakLineAtBeginning)return"\n"+(match[1]+(parseInt(match[2],10)+1))+". ";return"\n"}}(this),afterInsert:function(data){var caretPosition,line,scrollRelation,totalLines;return markdownCaretPositon?(setCaretPosition(data.textarea,markdownCaretPositon),caretPosition=markdownCaretPositon,markdownCaretPositon=!1):caretPosition=data.caretPosition,totalLines=data.textarea.value.split("\n").length,line=data.textarea.value.slice(0,+(caretPosition-1)+1||9e9).split("\n").length,scrollRelation=line/totalLines,$el.scrollTop(scrollRelation*$el[0].scrollHeight-$el.height()/2)}},markupSet:[{name:$tr.t("markdown-editor.heading-1"),key:"1",placeHolder:$tr.t("markdown-editor.placeholder"),closeWith:function(markItUp){return markdownTitle(markItUp,"=")}},{name:$tr.t("markdown-editor.heading-2"),key:"2",placeHolder:$tr.t("markdown-editor.placeholder"),closeWith:function(markItUp){return markdownTitle(markItUp,"-")}},{name:$tr.t("markdown-editor.heading-3"),key:"3",openWith:"### ",placeHolder:$tr.t("markdown-editor.placeholder")},{separator:"---------------"},{name:$tr.t("markdown-editor.bold"),key:"B",openWith:"**",closeWith:"**"},{name:$tr.t("markdown-editor.italic"),key:"I",openWith:"_",closeWith:"_"},{name:$tr.t("markdown-editor.strike"),key:"S",openWith:"~~",closeWith:"~~"},{separator:"---------------"},{name:$tr.t("markdown-editor.bulleted-list"),openWith:"- "},{name:$tr.t("markdown-editor.numeric-list"),openWith:function(markItUp){return markItUp.line+". "}},{separator:"---------------"},{name:$tr.t("markdown-editor.picture"),key:"P",replaceWith:'![[![Alternative text]!]]([![Url:!:http://]!] "[![Title]!]")'},{name:$tr.t("markdown-editor.link"),key:"L",openWith:"[",closeWith:']([![Url:!:http://]!] "[![Title]!]")',placeHolder:$tr.t("markdown-editor.link-placeholder")},{separator:"---------------"},{name:$tr.t("markdown-editor.quotes"),openWith:"> "},{name:$tr.t("markdown-editor.code-block"),openWith:"```\n",closeWith:"\n```"},{separator:"---------------"},{name:$tr.t("markdown-editor.preview"),call:preview,className:"preview-icon"}],afterInsert:function(event){var target;return target=angular.element(event.textarea),$model.$setViewValue(target.val())}},markdownTitle=function(markItUp,char){var heading,i,n,_i,_ref;for(heading="",n=$.trim(markItUp.selection||markItUp.placeHolder).length,i=_i=0,_ref=n-1;_ref>=0?_ref>=_i:_i>=_ref;i=_ref>=0?++_i:--_i)heading+=char;return"\n"+heading+"\n"},element.markItUp(markdownSettings),element.on("keypress",function(){return $scope.$apply()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgMarkitup",["$rootScope","$tgResources","$tgI18n","$selectedText","$tgTemplate",tgMarkitupDirective])}.call(this),function(){var BacklogFiltersDirective,bindOnce,debounceLeading,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,debounceLeading=this.taiga.debounceLeading,module=angular.module("taigaBacklog"),BacklogFiltersDirective=function($log,$location,$templates){var link,template,templateSelected;return template=$templates.get("backlog/filters.html",!0),templateSelected=$templates.get("backlog/filter-selected.html",!0),link=function($scope,$el){var $ctrl,initializeSelectedFilters,renderFilters,renderSelectedFilters,selectQFilter,selectedFilters,showCategories,showFilters,toggleFilterSelection;return $ctrl=$el.closest(".wrapper").controller(),selectedFilters=[],showFilters=function(title,type){return $el.find(".filters-cats").hide(),$el.find(".filter-list").removeClass("hidden"),$el.find("h2.breadcrumb").removeClass("hidden"),$el.find("h2 a.subfilter span.title").html(title),$el.find("h2 a.subfilter span.title").prop("data-type",type)},showCategories=function(){return $el.find(".filters-cats").show(),$el.find(".filter-list").addClass("hidden"),$el.find("h2.breadcrumb").addClass("hidden")},initializeSelectedFilters=function(filters){var name,val,values,_i,_len;showCategories(),selectedFilters=[];for(name in filters)for(values=filters[name],_i=0,_len=values.length;_len>_i;_i++)val=values[_i],val.selected&&selectedFilters.push(val);return renderSelectedFilters()},renderSelectedFilters=function(){var html;return _.map(selectedFilters,function(){return function(f){return f.color?f.style="border-left: 3px solid "+f.color:void 0}}(this)),html=templateSelected({filters:selectedFilters}),$el.find(".filters-applied").html(html)},renderFilters=function(filters){var html;return _.map(filters,function(){return function(f){return f.color?f.style="border-left: 3px solid "+f.color:void 0}}(this)),html=template({filters:filters}),$el.find(".filter-list").html(html)},toggleFilterSelection=function(type,id){var currentFiltersType,filter,filters;return filters=$scope.filters[type],filter=_.find(filters,{id:taiga.toString(id)}),filter.selected=!filter.selected,filter.selected?(selectedFilters.push(filter),$scope.$apply(function(){return $ctrl.selectFilter(type,id),$ctrl.filterVisibleUserstories()})):(selectedFilters=_.reject(selectedFilters,filter),$scope.$apply(function(){return $ctrl.unselectFilter(type,id),$ctrl.filterVisibleUserstories()})),renderSelectedFilters(selectedFilters),currentFiltersType=$el.find("h2 a.subfilter span.title").prop("data-type"),type===currentFiltersType&&renderFilters(_.reject(filters,"selected")),$ctrl.loadUserstories()},selectQFilter=debounceLeading(100,function(value){return void 0!==value?(0===value.length?$ctrl.replaceFilter("q",null):$ctrl.replaceFilter("q",value),$ctrl.loadUserstories()):void 0}),$scope.$watch("filtersQ",selectQFilter),$scope.$on("filters:loaded",function(ctx,filters){return initializeSelectedFilters(filters)}),$el.on("click",".filters-cats > ul > li > a",function(event){var tags,target;return event.preventDefault(),target=angular.element(event.currentTarget),tags=$scope.filters[target.data("type")],renderFilters(_.reject(tags,"selected")),showFilters(target.attr("title"),target.data("type"))}),$el.on("click",".filters-inner > .filters-step-cat > .breadcrumb > .back",function(event){return event.preventDefault(),showCategories()}),$el.on("click",".filters-applied a",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),id=target.data("id"),type=target.data("type"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),target.hasClass("active")?target.removeClass("active"):target.addClass("active"),id=target.data("id"),type=target.data("type"),toggleFilterSelection(type,id)})},{link:link}},module.directive("tgBacklogFilters",["$log","$tgLocation","$tgTemplate",BacklogFiltersDirective])}.call(this),function(){var CreateEditSprint,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaBacklog"),CreateEditSprint=function($repo,$confirm,$rs,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var createSprint,hasErrors,remove,submit,submitButton;return hasErrors=!1,createSprint=!0,$scope.sprint={project:null,name:null,estimated_start:null,estimated_finish:null},submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,newSprint,promise,target;return event.preventDefault(),target=angular.element(event.currentTarget),form=$el.find("form").checksley(),form.validate()?(hasErrors=!1,newSprint=angular.copy($scope.sprint),broadcastEvent=null,createSprint?(newSprint.estimated_start=moment(newSprint.estimated_start).format("YYYY-MM-DD"),newSprint.estimated_finish=moment(newSprint.estimated_finish).format("YYYY-MM-DD"),promise=$repo.create("milestones",newSprint),broadcastEvent="sprintform:create:success"):(newSprint.setAttr("estimated_start",moment(newSprint.estimated_start).format("YYYY-MM-DD")),newSprint.setAttr("estimated_finish",moment(newSprint.estimated_finish).format("YYYY-MM-DD")),promise=$repo.save(newSprint),broadcastEvent="sprintform:edit:success"),$loading.start(submitButton),promise.then(function(data){return $loading.finish(submitButton),createSprint&&($scope.sprintsCounter+=1),$rootscope.$broadcast(broadcastEvent,data),lightboxService.close($el)}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("light-error",data._error_message):data.__all__?$confirm.notify("light-error",data.__all__[0]):void 0})):(hasErrors=!0,void $el.find(".last-sprint-name").addClass("disappear"))}}(this)),remove=function(){var message,title;return title="Delete sprint",message=$scope.sprint.name,$confirm.askOnDelete(title,message).then(function(){return function(finish){var onError,onSuccess;return onSuccess=function(){return finish(),$scope.milestonesCounter-=1,lightboxService.close($el),$rootscope.$broadcast("sprintform:remove:success")},onError=function(){return finish(!1),$confirm.notify("error")},$repo.remove($scope.sprint).then(onSuccess,onError)}}(this))},$scope.$on("sprintform:create",function(event,projectId){var estimatedFinish,estimatedStart,lastSprint,lastSprintNameDom;return createSprint=!0,$scope.sprint.project=projectId,$scope.sprint.name=null,$scope.sprint.slug=null,lastSprint=$scope.sprints[0],estimatedStart=moment(),$scope.sprint.estimated_start?estimatedStart=moment($scope.sprint.estimated_start):null!=lastSprint&&(estimatedStart=moment(lastSprint.estimated_finish)),$scope.sprint.estimated_start=estimatedStart.format("DD MMM YYYY"),estimatedFinish=moment().add(2,"weeks"),$scope.sprint.estimated_finish?estimatedFinish=moment($scope.sprint.estimated_finish):null!=lastSprint&&(estimatedFinish=moment(lastSprint.estimated_finish).add(2,"weeks")),$scope.sprint.estimated_finish=estimatedFinish.format("DD MMM YYYY"),lastSprintNameDom=$el.find(".last-sprint-name"),null!=(null!=lastSprint?lastSprint.name:void 0)&&lastSprintNameDom.html(" last sprint is "+lastSprint.name+" ;-) "),$el.find(".delete-sprint").addClass("hidden"),$el.find(".title").text("New sprint"),$el.find(".button-green").text("Create"),lightboxService.open($el),$el.find(".sprint-name").focus()}),$scope.$on("sprintform:edit",function(ctx,sprint){return createSprint=!1,$scope.$apply(function(){return $scope.sprint=sprint,$scope.sprint.estimated_start=moment($scope.sprint.estimated_start).format("DD MMM YYYY"),$scope.sprint.estimated_finish=moment($scope.sprint.estimated_finish).format("DD MMM YYYY")}),$el.find(".delete-sprint").removeClass("hidden"),$el.find(".title").text("Edit sprint"),$el.find(".button-green").text("Save"),lightboxService.open($el),$el.find(".sprint-name").focus().select(),$el.find(".last-sprint-name").addClass("disappear")}),$el.on("keyup",".sprint-name",function(){return $el.find(".sprint-name").val().length>0||hasErrors?$el.find(".last-sprint-name").addClass("disappear"):$el.find(".last-sprint-name").removeClass("disappear")}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".delete-sprint .icon-delete",function(event){return event.preventDefault(),remove()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateEditSprint",["$tgRepo","$tgConfirm","$tgResources","$rootScope","lightboxService","$tgLoading",CreateEditSprint])}.call(this),function(){var BacklogController,BacklogDirective,TgBacklogProgressBarDirective,UsPointsDirective,UsRolePointsSelectorDirective,bindMethods,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,tgBacklogGraphDirective,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaBacklog"),BacklogController=function(_super){function BacklogController(scope,rootscope,repo,confirm,rs,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Backlog",this.showTags=!1,this.activeFilters=!1,this.excludeClosedSprints=!0,this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Backlog - "+_this.scope.project.name),_this.rs.userstories.getShowTags(_this.scope.projectId)?(_this.showTags=!0,_this.scope.$broadcast("showTags",_this.showTags)):void 0}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(BacklogController,_super),BacklogController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],BacklogController.prototype.initializeEventHandlers=function(){return this.scope.$on("usform:bulk:success",function(_this){return function(){return _this.loadUserstories(),_this.loadProjectStats(),_this.analytics.trackEvent("userstory","create","bulk create userstory on backlog",1)}}(this)),this.scope.$on("sprintform:create:success",function(_this){return function(){return _this.loadSprints(),_this.loadProjectStats(),_this.analytics.trackEvent("sprint","create","create sprint on backlog",1)}}(this)),this.scope.$on("usform:new:success",function(_this){return function(){return _this.loadUserstories(),_this.loadProjectStats(),_this.analytics.trackEvent("userstory","create","create userstory on backlog",1)}}(this)),this.scope.$on("sprintform:edit:success",function(_this){return function(){return _this.loadProjectStats()}}(this)),this.scope.$on("sprintform:remove:success",function(_this){return function(){return _this.loadSprints(),_this.loadProjectStats(),_this.loadUserstories()}}(this)),this.scope.$on("usform:edit:success",function(_this){return function(){return _this.loadUserstories()}}(this)),this.scope.$on("sprint:us:move",this.moveUs),this.scope.$on("sprint:us:moved",this.loadSprints),this.scope.$on("sprint:us:moved",this.loadProjectStats),this.scope.$on("backlog:toggle-closed-sprints-visualization",this.toggleClosedSprintsVisualization)},BacklogController.prototype.initializeSubscription=function(){var routingKey1,routingKey2;return routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.loadUserstories(),_this.loadSprints()}}(this)),routingKey2="changes.project."+this.scope.projectId+".milestones",this.events.subscribe(this.scope,routingKey2,function(_this){return function(){return _this.loadSprints()}}(this))},BacklogController.prototype.toggleShowTags=function(){return this.scope.$apply(function(_this){return function(){return _this.showTags=!_this.showTags,_this.rs.userstories.storeShowTags(_this.scope.projectId,_this.showTags)}}(this))},BacklogController.prototype.toggleActiveFilters=function(){return this.activeFilters=!this.activeFilters},BacklogController.prototype.loadProjectStats=function(){return this.rs.projects.stats(this.scope.projectId).then(function(_this){return function(stats){return _this.scope.stats=stats,_this.scope.stats.completedPercentage=stats.total_points?Math.round(100*stats.closed_points/stats.total_points):0,stats}}(this))},BacklogController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},BacklogController.prototype.loadSprints=function(){var params;return params={},this.excludeClosedSprints&&(params.closed=!1),this.rs.sprints.list(this.scope.projectId,params).then(function(_this){return function(sprints){var sprint,_i,_len;for(_i=0,_len=sprints.length;_len>_i;_i++)sprint=sprints[_i],sprint.user_stories=_.sortBy(sprint.user_stories,"sprint_order");return _this.scope.sprints=sprints,_this.scope.openSprints=_.filter(sprints,function(sprint){return!sprint.closed}).reverse(),_this.scope.closedSprints=_.filter(sprints,function(sprint){return sprint.closed}),_this.excludeClosedSprints||(_this.scope.totalClosedMilestones=_this.scope.closedSprints.length),_this.scope.sprintsCounter=sprints.length,_this.scope.sprintsById=groupBy(sprints,function(x){return x.id}),_this.rootscope.$broadcast("sprints:loaded",sprints),sprints}}(this))},BacklogController.prototype.resetFilters=function(){var selectedStatuses,selectedTags;return selectedTags=_.filter(this.scope.filters.tags,"selected"),selectedStatuses=_.filter(this.scope.filters.statuses,"selected"),this.scope.filtersQ="",_.each([selectedTags,selectedStatuses],function(_this){return function(filterGrp){return _.each(filterGrp,function(item){var filter,filters;return filters=_this.scope.filters[item.type],filter=_.find(filters,{id:taiga.toString(item.id)}),filter.selected=!1,_this.unselectFilter(item.type,item.id)})}}(this)),this.loadUserstories()},BacklogController.prototype.loadUserstories=function(){var promise;return this.scope.httpParams=this.getUrlFilters(),this.rs.userstories.storeQueryParams(this.scope.projectId,this.scope.httpParams),promise=this.q.all([this.refreshTagsColors(),this.rs.userstories.listUnassigned(this.scope.projectId,this.scope.httpParams)]),promise.then(function(_this){return function(data){var userstories;return userstories=data[1],_this.scope.userstories=_.sortBy(userstories,"backlog_order"),_this.generateFilters(),_this.filterVisibleUserstories(),_this.rootscope.$broadcast("filters:loaded",_this.scope.filters),scopeDefer(_this.scope,function(){return _this.scope.$broadcast("userstories:loaded")}),userstories}}(this))},BacklogController.prototype.loadBacklog=function(){return this.q.all([this.loadProjectStats(),this.loadSprints(),this.loadUserstories()])},BacklogController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.totalClosedMilestones=project.total_closed_milestones,_this.scope.$emit("project:loaded",project),_this.scope.points=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(x){return x.id}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.usStatusList=_.sortBy(project.us_statuses,"id"),project}}(this))},BacklogController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription()}}(this)),promise.then(function(_this){return function(){return _this.loadBacklog()}}(this))},BacklogController.prototype.toggleClosedSprintsVisualization=function(){return this.excludeClosedSprints=!this.excludeClosedSprints,this.loadSprints()},BacklogController.prototype.filterVisibleUserstories=function(){var selectedStatuses,selectedTags;return this.scope.visibleUserstories=[],selectedTags=_.filter(this.scope.filters.tags,"selected"),selectedTags=_.map(selectedTags,"name"),this.scope.visibleUserstories=0===selectedTags.length?_.clone(this.scope.userstories,!1):_.reject(this.scope.userstories,function(){return function(us){return 0===_.intersection(selectedTags,us.tags).length?!0:!1}}(this)),selectedStatuses=_.filter(this.scope.filters.statuses,"selected"),selectedStatuses=_.map(selectedStatuses,"id"),selectedStatuses.length>0&&(this.scope.visibleUserstories=_.reject(this.scope.visibleUserstories,function(){return function(us){var res;return res=_.find(selectedStatuses,function(x){return x===taiga.toString(us.status)}),!res}}(this))),this.rs.userstories.storeQueryParams(this.scope.projectId,{status:selectedStatuses,tags:selectedTags,project:this.scope.projectId,milestone:null})},BacklogController.prototype.prepareBulkUpdateData=function(uses,field){return null==field&&(field="backlog_order"),_.map(uses,function(x){return{us_id:x.id,order:x[field]}})},BacklogController.prototype.resortUserStories=function(uses,field){var index,item,items,_i,_len;for(null==field&&(field="backlog_order"),items=[],index=_i=0,_len=uses.length;_len>_i;index=++_i)item=uses[index],item[field]=index,item.isModified()&&items.push(item);return items},BacklogController.prototype.moveUs=function(ctx,usList,newUsIndex,newSprintId){var data,items,newSprint,oldSprintId,project,promise,promises,us,userstories,_i,_j,_k,_len,_len1,_len2;if(oldSprintId=usList[0].milestone,project=usList[0].project,newSprintId===oldSprintId)return items=null,userstories=null,userstories=null===newSprintId?this.scope.userstories:this.scope.sprintsById[newSprintId].user_stories,this.scope.$apply(function(){var args,key,r,us,_i,_len;for(key=_i=0,_len=usList.length;_len>_i;key=++_i)us=usList[key],r=userstories.indexOf(us),userstories.splice(r,1);return args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(userstories,args)}),null===newSprintId?(items=this.resortUserStories(userstories,"backlog_order"),data=this.prepareBulkUpdateData(items,"backlog_order"),this.rs.userstories.bulkUpdateBacklogOrder(project,data).then(function(_this){return function(){var us,_i,_len,_results;for(_results=[],_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results}}(this))):(items=this.resortUserStories(userstories,"sprint_order"),data=this.prepareBulkUpdateData(items,"sprint_order"),this.rs.userstories.bulkUpdateSprintOrder(project,data).then(function(_this){return function(){var us,_i,_len,_results;for(_results=[],_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results}}(this))),promise;if(null===newSprintId){for(_i=0,_len=usList.length;_len>_i;_i++)us=usList[_i],us.milestone=null;return this.scope.$apply(function(_this){return function(){var args,key,r,sprint,_j,_len1,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(_this.scope.userstories,args),Array.prototype.splice.apply(_this.scope.visibleUserstories,args),_this.filterVisibleUserstories(),sprint=_this.scope.sprintsById[oldSprintId],_results=[],key=_j=0,_len1=usList.length;_len1>_j;key=++_j)us=usList[key],r=sprint.user_stories.indexOf(us),_results.push(sprint.user_stories.splice(r,1));return _results}}(this)),promise=this.repo.save(us),promise=promise.then(function(_this){return function(){return items=_this.resortUserStories(_this.scope.userstories,"backlog_order"),data=_this.prepareBulkUpdateData(items,"backlog_order"),_this.rs.userstories.bulkUpdateBacklogOrder(us.project,data).then(function(){return _this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId)})}}(this)),promise.then(null,function(){return console.log("FAIL")}),promise}if(newSprint=this.scope.sprintsById[newSprintId],null===oldSprintId){for(_j=0,_len1=usList.length;_len1>_j;_j++)us=usList[_j],us.milestone=newSprintId; +this.scope.$apply(function(_this){return function(){var args,key,r,_k,_len2,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(newSprint.user_stories,args),_results=[],key=_k=0,_len2=usList.length;_len2>_k;key=++_k)us=usList[key],r=_this.scope.visibleUserstories.indexOf(us),_this.scope.visibleUserstories.splice(r,1),r=_this.scope.userstories.indexOf(us),_results.push(_this.scope.userstories.splice(r,1));return _results}}(this))}else{for(_k=0,_len2=usList.length;_len2>_k;_k++)us=usList[_k],us.milestone=newSprintId;this.scope.$apply(function(_this){return function(){var args,oldSprint,r,_l,_len3,_results;for(args=[newUsIndex,0].concat(usList),Array.prototype.splice.apply(newSprint.user_stories,args),_results=[],_l=0,_len3=usList.length;_len3>_l;_l++)us=usList[_l],oldSprint=_this.scope.sprintsById[oldSprintId],r=oldSprint.user_stories.indexOf(us),_results.push(oldSprint.user_stories.splice(r,1));return _results}}(this))}return promises=_.map(usList,function(_this){return function(us){return _this.repo.save(us)}}(this)),promise=this.q.all(promises).then(function(_this){return function(){return items=_this.resortUserStories(newSprint.user_stories,"sprint_order"),data=_this.prepareBulkUpdateData(items,"sprint_order"),_this.rs.userstories.bulkUpdateSprintOrder(project,data).then(function(){return _this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId)}),_this.rs.userstories.bulkUpdateBacklogOrder(project,data).then(function(){var _l,_len3,_results;for(_results=[],_l=0,_len3=usList.length;_len3>_l;_l++)us=usList[_l],_results.push(_this.rootscope.$broadcast("sprint:us:moved",us,oldSprintId,newSprintId));return _results})}}(this)),promise.then(null,function(){return console.log("FAIL")}),promise},BacklogController.prototype.getUrlFilters=function(){return _.pick(this.location.search(),"statuses","tags","q")},BacklogController.prototype.generateFilters=function(){var isSelected,name,plainStatuses,plainTags,searchdata,urlfilters,val,value,_i,_len,_ref;urlfilters=this.getUrlFilters(),urlfilters.q&&(this.scope.filtersQ=urlfilters.q),searchdata={};for(name in urlfilters)for(value=urlfilters[name],null==searchdata[name]&&(searchdata[name]={}),_ref=taiga.toString(value).split(","),_i=0,_len=_ref.length;_len>_i;_i++)val=_ref[_i],searchdata[name][val]=!0;return isSelected=function(type,id){return null!=searchdata[type]&&searchdata[type][id]?!0:!1},this.scope.filters={},plainTags=_.flatten(_.filter(_.map(this.scope.userstories,"tags"))),plainTags.sort(),this.scope.filters.tags=_.map(_.countBy(plainTags),function(_this){return function(v,k){var obj;return obj={id:k,type:"tags",name:k,color:_this.scope.project.tags_colors[k],count:v},isSelected("tags",obj.id)&&(obj.selected=!0),obj}}(this)),plainStatuses=_.map(this.scope.userstories,"status"),plainStatuses=_.filter(plainStatuses,function(){return function(status){return status?status:void 0}}(this)),this.scope.filters.statuses=_.map(_.countBy(plainStatuses),function(_this){return function(v,k){var obj;return obj={id:k,type:"statuses",name:_this.scope.usStatusById[k].name,color:_this.scope.usStatusById[k].color,count:v},isSelected("statuses",obj.id)&&(obj.selected=!0),obj}}(this)),this.scope.filters},BacklogController.prototype.editUserStory=function(us){return this.rootscope.$broadcast("usform:edit",us)},BacklogController.prototype.deleteUserStory=function(us){var message,title;return title="Delete User Story",message=us.subject,this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var promise;return _this.scope.userstories=_.without(_this.scope.userstories,us),_this.filterVisibleUserstories(),promise=_this.repo.remove(us),promise.then(function(){return finish(),_this.loadBacklog()}),promise.then(null,function(){return finish(!1),_this.confirm.notify("error")})}}(this))},BacklogController.prototype.addNewUs=function(type){switch(type){case"standard":return this.rootscope.$broadcast("usform:new",this.scope.projectId,this.scope.project.default_us_status,this.scope.usStatusList);case"bulk":return this.rootscope.$broadcast("usform:bulk",this.scope.projectId,this.scope.project.default_us_status)}},BacklogController.prototype.addNewSprint=function(){return this.rootscope.$broadcast("sprintform:create",this.scope.projectId)},BacklogController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("BacklogController",BacklogController),BacklogDirective=function($repo,$rootscope){var doomLineTemplate,link,linkDoomLine,linkFilters,linkToolbar,showHideFilter,showHideTags;return doomLineTemplate=_.template('
    Project Scope [Doomline]
    '),linkDoomLine=function($scope,$el){var addDoomLineDom,getUsItems,reloadDoomLine,removeDoomlineDom;return reloadDoomLine=function(){var current_sum,element,elements,scope,stats,total_points,_i,_len,_results;if(null!=$scope.stats){for(removeDoomlineDom(),elements=getUsItems(),stats=$scope.stats,total_points=stats.total_points,current_sum=stats.assigned_points,_results=[],_i=0,_len=elements.length;_len>_i;_i++)if(element=elements[_i],scope=element.scope(),null!=scope.us){if(current_sum+=scope.us.total_points,current_sum>total_points){addDoomLineDom(element);break}_results.push(void 0)}return _results}},removeDoomlineDom=function(){return $el.find(".doom-line").remove()},addDoomLineDom=function(element){return null!=element?element.before(doomLineTemplate({})):void 0},getUsItems=function(){var rowElements;return rowElements=$el.find(".backlog-table-body .us-item-row"),_.map(rowElements,function(x){return angular.element(x)})},$scope.$on("userstories:loaded",reloadDoomLine),$scope.$watch("stats",reloadDoomLine)},linkToolbar=function($scope,$el,$attrs,$ctrl){var moveToCurrentSprint;return moveToCurrentSprint=function(selectedUss){var extraPoints,totalExtraPoints,ussCurrent;return ussCurrent=_($scope.userstories),$scope.userstories=ussCurrent.without.apply(ussCurrent,selectedUss).value(),extraPoints=_.map(selectedUss,function(v){return v.total_points}),totalExtraPoints=_.reduce(extraPoints,function(acc,num){return acc+num}),$scope.sprints[0].user_stories=_.union($scope.sprints[0].user_stories,selectedUss),$scope.sprints[0].total_points+=totalExtraPoints,$ctrl.filterVisibleUserstories(),$repo.saveAll(selectedUss).then(function(){return $ctrl.loadSprints(),$ctrl.loadProjectStats()})},$el.on("change",".backlog-table-body .user-stories input:checkbox",function(event){var moveToCurrentSprintDom,selectedUsDom,target;return target=angular.element(event.currentTarget),moveToCurrentSprintDom=$el.find("#move-to-current-sprint"),selectedUsDom=$el.find(".backlog-table-body .user-stories input:checkbox:checked"),selectedUsDom.length>0&&$scope.sprints.length>0?moveToCurrentSprintDom.show():moveToCurrentSprintDom.hide(),target.closest(".us-item-row").toggleClass("ui-multisortable-multiple")}),$el.on("click","#move-to-current-sprint",function(){return function(){var ussDom,ussToMove;return ussDom=$el.find(".backlog-table-body .user-stories input:checkbox:checked"),ussToMove=_.map(ussDom,function(item){var itemScope;return itemScope=angular.element(item).scope(),itemScope.us.milestone=$scope.sprints[0].id,itemScope.us}),$scope.$apply(_.partial(moveToCurrentSprint,ussToMove))}}(this)),$el.on("click","#show-tags",function(event){return event.preventDefault(),$ctrl.toggleShowTags(),showHideTags($ctrl)})},showHideTags=function($ctrl){var elm;return elm=angular.element("#show-tags"),$ctrl.showTags?(elm.addClass("active"),elm.find(".text").text("Hide Tags")):(elm.removeClass("active"),elm.find(".text").text("Show Tags"))},showHideFilter=function($scope,$el,$ctrl){var sidebar,target;return sidebar=$el.find("sidebar.filters-bar"),sidebar.one("transitionend",function(){return timeout(150,function(){return $rootscope.$broadcast("resize"),$(".burndown").css("visibility","visible")})}),target=angular.element("#show-filters-button"),$(".burndown").css("visibility","hidden"),sidebar.toggleClass("active"),target.toggleClass("active"),toggleText(target.find(".text"),["Remove Filters","Show Filters"]),sidebar.hasClass("active")||$ctrl.resetFilters(),$ctrl.toggleActiveFilters()},linkFilters=function($scope,$el,$attrs,$ctrl){return $scope.filtersSearch={},$el.on("click","#show-filters-button",function(event){return event.preventDefault(),$scope.$apply(function(){return showHideFilter($scope,$el,$ctrl)})})},link=function($scope,$el,$attrs){var $ctrl,filters;return $ctrl=$el.controller(),linkToolbar($scope,$el,$attrs,$ctrl),linkFilters($scope,$el,$attrs,$ctrl),linkDoomLine($scope,$el,$attrs,$ctrl),$el.find(".backlog-table-body").disableSelection(),filters=$ctrl.getUrlFilters(),(filters.statuses||filters.tags||filters.q)&&showHideFilter($scope,$el,$ctrl),$scope.$on("showTags",function(){return showHideTags($ctrl)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklog",["$tgRepo","$rootScope",BacklogDirective]),UsRolePointsSelectorDirective=function($rootscope,$template){var link,selectionTemplate;return selectionTemplate=$template.get("backlog/us-role-points-popover.html",!0),link=function($scope,$el){return bindOnce($scope,"project",function(project){var numberOfRoles,roles;return roles=_.filter(project.roles,"computable"),numberOfRoles=_.size(roles),numberOfRoles>1?$el.append(selectionTemplate({roles:roles})):($el.find(".icon-arrow-bottom").remove(),$el.find(".header-points").addClass("not-clickable"))}),$scope.$on("uspoints:select",function(ctx,roleId,roleName){return $el.find(".popover").popover().close(),$el.find(".header-points").html(""+roleName+"/Total")}),$scope.$on("uspoints:clear-selection",function(){return $el.find(".popover").popover().close(),$el.find(".header-points").text("Points")}),$el.on("click",function(event){var target;return target=angular.element(event.target),(target.is("span")||target.is("div"))&&event.stopPropagation(),$el.find(".popover").popover().open()}),$el.on("click",".clear-selection",function(event){return event.preventDefault(),event.stopPropagation(),$rootscope.$broadcast("uspoints:clear-selection")}),$el.on("click",".role",function(event){var rolScope,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),rolScope=target.scope(),$rootscope.$broadcast("uspoints:select",target.data("role-id"),target.text())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUsRolePointsSelector",["$rootScope","$tgTemplate",UsRolePointsSelectorDirective]),UsPointsDirective=function($repo,$tgTemplate){var link,pointsTemplate,rolesTemplate;return rolesTemplate=$tgTemplate.get("backlog/us-points-roles-popover.html",!0),pointsTemplate=$tgTemplate.get("backlog/us-points-popover.html",!0),link=function($scope,$el,$attrs){var $ctrl,calculateTotalPoints,computableRoles,numberOfRoles,renderPoints,renderPointsSelector,renderRolesSelector,roles,selectedRoleId,updatePointsRoles,updatingSelectedRoleId,us;return $ctrl=$el.controller(),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=null,selectedRoleId=null,numberOfRoles=_.size(us.points),1===numberOfRoles&&(selectedRoleId=_.keys(us.points)[0]),roles=[],updatePointsRoles=function(){return roles=_.map(computableRoles,function(role){var pointId,pointObj;return pointId=us.points[role.id],pointObj=$scope.pointsById[pointId],role=_.clone(role,!0),role.points=null!=pointObj.value?pointObj.value:"?",role})},computableRoles=_.filter($scope.project.roles,"computable"),updatePointsRoles(),0===roles.length&&($el.find(".icon-arrow-bottom").remove(),$el.find("a.us-points").addClass("not-clickable")),renderPointsSelector=function(us,roleId){var html,points;return points=_.map($scope.project.points,function(point){return point=_.clone(point,!0),point.selected=us.points[roleId]===point.id?!1:!0,point}),html=pointsTemplate({points:points}),$el.find(".popover").popover().close(),$el.find(".pop-points-open").remove(),$el.append(html),null==$el.find(".pop-role:visible").css("left")&&$el.find(".pop-points-open").css("left","110px"),$el.find(".pop-points-open").popover().open()},renderRolesSelector=function(){var html;return updatePointsRoles(),html=rolesTemplate({roles:roles}),$el.append(html),$el.find(".pop-role").popover().open(function(){return $(this).remove()})},renderPoints=function(us,roleId){var dom,pointId,pointObj,totalPoints;return dom=$el.find("a > span.points-value"),null===roleId||1===numberOfRoles?(totalPoints=null!=us.total_points?us.total_points:"?",dom.text(totalPoints),dom.parent().prop("title",totalPoints)):(pointId=us.points[roleId],pointObj=$scope.pointsById[pointId],dom.html(""+pointObj.name+" / "+us.total_points+""),dom.parent().prop("title",""+pointObj.name+" / "+us.total_points))},calculateTotalPoints=function(){var values;return values=_.map(us.points,function(v){return $scope.pointsById[v].value}),values=_.filter(values,function(num){return null!=num}),0===values.length?"?":_.reduce(values,function(acc,num){return acc+num})},$scope.$watch($attrs.tgBacklogUsPoints,function(us){return us?renderPoints(us,selectedRoleId):void 0}),$scope.$on("uspoints:select",function(ctx,roleId){return us=$scope.$eval($attrs.tgBacklogUsPoints),renderPoints(us,roleId),selectedRoleId=roleId}),$scope.$on("uspoints:clear-selection",function(){return us=$scope.$eval($attrs.tgBacklogUsPoints),renderPoints(us,null),selectedRoleId=null}),roles.length>0&&($el.on("click","a.us-points span",function(event){return event.preventDefault(),event.stopPropagation(),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=selectedRoleId,null!=selectedRoleId?renderPointsSelector(us,selectedRoleId):renderRolesSelector(us)}),$el.on("click",".role",function(event){var popRolesDom,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),us=$scope.$eval($attrs.tgBacklogUsPoints),updatingSelectedRoleId=target.data("role-id"),popRolesDom=$el.find(".pop-role"),popRolesDom.find("a").removeClass("active"),popRolesDom.find("a[data-role-id='"+updatingSelectedRoleId+"']").addClass("active"),renderPointsSelector(us,updatingSelectedRoleId)}),$el.on("click",".point",function(event){var points,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),$el.find(".pop-points-open").hide(),$el.find(".pop-role").hide(),us=$scope.$eval($attrs.tgBacklogUsPoints),points=_.clone(us.points,!0),points[updatingSelectedRoleId]=target.data("point-id"),$scope.$apply(function(){return us.points=points,us.total_points=calculateTotalPoints(us),renderPoints(us,selectedRoleId),$repo.save(us).then(function(){return $repo.refresh(us).then(function(){return $ctrl.loadProjectStats()})})})})),bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_us")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogUsPoints",["$tgRepo","$tgTemplate",UsPointsDirective]),tgBacklogGraphDirective=function(){var link,redrawChart;return redrawChart=function(element,dataToDraw){var client_increment_line,colors,data,evolution_line,milestonesRange,optimal_line,options,team_increment_line,width,zero_line,_results;return width=element.width(),element.height(width/6),milestonesRange=function(){_results=[];for(var _i=0,_ref=dataToDraw.milestones.length-1;_ref>=0?_ref>=_i:_i>=_ref;_ref>=0?_i++:_i--)_results.push(_i);return _results}.apply(this),data=[],zero_line=_.map(dataToDraw.milestones,function(){return 0}),data.push({data:_.zip(milestonesRange,zero_line),lines:{fillColor:"rgba(0,0,0,0)"},points:{show:!1}}),optimal_line=_.map(dataToDraw.milestones,function(ml){return ml.optimal}),data.push({data:_.zip(milestonesRange,optimal_line),lines:{fillColor:"rgba(120,120,120,0.2)"}}),evolution_line=_.filter(_.map(dataToDraw.milestones,function(ml){return ml.evolution}),function(evolution){return null!=evolution}),data.push({data:_.zip(milestonesRange,evolution_line),lines:{fillColor:"rgba(102,153,51,0.3)"}}),team_increment_line=_.map(dataToDraw.milestones,function(ml){return-ml["team-increment"]}),data.push({data:_.zip(milestonesRange,team_increment_line),lines:{fillColor:"rgba(153,51,51,0.3)"}}),client_increment_line=_.map(dataToDraw.milestones,function(ml){return-ml["team-increment"]-ml["client-increment"]}),data.push({data:_.zip(milestonesRange,client_increment_line),lines:{fillColor:"rgba(255,51,51,0.3)"}}),colors=["rgba(0,0,0,1)","rgba(120,120,120,0.2)","rgba(102,153,51,1)","rgba(153,51,51,1)","rgba(255,51,51,1)"],options={grid:{borderWidth:{top:0,right:1,left:0,bottom:0},borderColor:"#ccc",hoverable:!0},xaxis:{ticks:dataToDraw.milestones.length,axisLabel:"Sprints",axisLabelUseCanvas:!0,axisLabelFontSizePixels:14,axisLabelFontFamily:"Verdana, Arial, Helvetica, Tahoma, sans-serif",axisLabelPadding:15,tickFormatter:function(){return""}},series:{shadowSize:0,lines:{show:!0,fill:!0},points:{show:!0,fill:!0,radius:4,lineWidth:2}},colors:colors,tooltip:!0,tooltipOpts:{content:function(label,xval,yval,flotItem){return 1===flotItem.seriesIndex?"Optimal pending points for sprint "+xval+" should be "+yval:2===flotItem.seriesIndex?"Real pending points for sprint "+xval+" is "+yval:3===flotItem.seriesIndex?"Incremented points by team requirements for sprint "+xval+" is "+Math.abs(yval):"Incremented points by client requirements for sprint "+xval+" is "+Math.abs(yval)}}},element.empty(),element.plot(data,options).data("plot")},link=function($scope,$el){var element;return element=angular.element($el),$scope.$watch("stats",function(){return null!=$scope.stats?(redrawChart(element,$scope.stats),$scope.$on("resize",function(){return redrawChart(element,$scope.stats)})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgGmBacklogGraph",tgBacklogGraphDirective),TgBacklogProgressBarDirective=function($template){var adjustPercentaje,link,render,template;return template=$template.get("backlog/progress-bar.html",!0),render=function(el,projectPointsPercentaje,closedPointsPercentaje){return el.html(template({projectPointsPercentaje:projectPointsPercentaje,closedPointsPercentaje:closedPointsPercentaje}))},adjustPercentaje=function(percentage){var adjusted;return adjusted=_.max([0,percentage]),adjusted=_.min([100,adjusted]),Math.round(adjusted)},link=function($scope,$el,$attrs){var element;return element=angular.element($el),$scope.$watch($attrs.tgBacklogProgressBar,function(stats){var closedPoints,closedPointsPercentaje,definedPoints,projectPointsPercentaje,totalPoints;return null!=stats?(totalPoints=stats.total_points,definedPoints=stats.defined_points,closedPoints=stats.closed_points,definedPoints>totalPoints?(projectPointsPercentaje=100*totalPoints/definedPoints,closedPointsPercentaje=100*closedPoints/definedPoints):(projectPointsPercentaje=100,closedPointsPercentaje=100*closedPoints/totalPoints),projectPointsPercentaje=adjustPercentaje(projectPointsPercentaje-3),closedPointsPercentaje=adjustPercentaje(closedPointsPercentaje-3),render($el,projectPointsPercentaje,closedPointsPercentaje)):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogProgressBar",["$tgTemplate",TgBacklogProgressBarDirective])}.call(this),function(){var BacklogEmptySortableDirective,BacklogSortableDirective,SprintSortableDirective,bindOnce,deleteElement,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,module=angular.module("taigaBacklog"),deleteElement=function(el){return el.scope().$destroy(),el.off(),el.remove()},BacklogSortableDirective=function($repo,$rs,$rootscope,$tgConfirm){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){var filterError;if(project.my_permissions.indexOf("modify_us")>-1)return filterError=function(){return $tgConfirm.notify("error","You can't drop on backlog when filters are open")},$el.sortable({connectWith:".sprint",containment:".wrapper",dropOnEmpty:!0,placeholder:"row us-item-row us-item-drag sortable-placeholder",scroll:!0,tolerance:"pointer",revert:!1,cursorAt:{right:15},stop:function(){return $el.hasClass("active-filters")?($el.sortable("cancel"),filterError()):void 0}}),$el.on("multiplesortreceive",function(event,ui){var itemIndex,itemUs;return $el.hasClass("active-filters")?(ui.source.sortable("cancel"),void filterError()):(itemUs=ui.item.scope().us,itemIndex=ui.item.index(),deleteElement(ui.item),$scope.$emit("sprint:us:move",[itemUs],itemIndex,null),ui.item.find("a").removeClass("noclick"))}),$el.on("multiplesortstop",function(event,ui){var index,items,us;if(0!==$(ui.items[0]).parent().length)return items=_.sortBy(ui.items,function(item){return $(item).index()}),index=_.min(_.map(items,function(item){return $(item).index()})),us=_.map(items,function(item){var itemUs;return item=$(item),itemUs=item.scope().us,setTimeout(function(){return function(){return item.find("a").removeClass("noclick")}}(this),300),itemUs}),$scope.$emit("sprint:us:move",us,index,null)}),$el.on("sortstart",function(event,ui){return ui.item.find("a").addClass("noclick")})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},BacklogEmptySortableDirective=function(){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?($el.sortable({dropOnEmpty:!0}),$el.on("sortreceive",function(event,ui){var itemIndex,itemUs;return itemUs=ui.item.scope().us,itemIndex=ui.item.index(),deleteElement(ui.item),$scope.$emit("sprint:us:move",[itemUs],itemIndex,null),ui.item.find("a").removeClass("noclick")})):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},SprintSortableDirective=function(){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?($el.sortable({scroll:!0,dropOnEmpty:!0,items:".sprint-table .milestone-us-item-row",connectWith:".sprint,.backlog-table-body,.empty-backlog"}),$el.on("multiplesortreceive",function(event,ui){var index,items,us;return items=_.sortBy(ui.items,function(item){return $(item).index()}),index=_.min(_.map(items,function(item){return $(item).index()})),us=_.map(items,function(item){var itemUs;return item=$(item),itemUs=item.scope().us,deleteElement(item),itemUs}),$scope.$emit("sprint:us:move",us,index,$scope.sprint.id)}),$el.on("multiplesortstop",function(event,ui){var itemIndex,itemUs;if(0!==ui.item.parent().length)return itemUs=ui.item.scope().us,itemIndex=ui.item.index(),setTimeout(function(){return function(){return ui.item.find("a").removeClass("noclick")}}(this),300),$scope.$emit("sprint:us:move",[itemUs],itemIndex,$scope.sprint.id)}),$el.on("sortstart",function(event,ui){return ui.item.find("a").addClass("noclick")})):void 0})},{link:link}},module.directive("tgBacklogSortable",["$tgRepo","$tgResources","$rootScope","$tgConfirm",BacklogSortableDirective]),module.directive("tgBacklogEmptySortable",["$tgRepo","$tgResources","$rootScope",BacklogEmptySortableDirective]),module.directive("tgSprintSortable",["$tgRepo","$tgResources","$rootScope",SprintSortableDirective])}.call(this),function(){var BacklogSprintDirective,BacklogSprintHeaderDirective,ToggleExcludeClosedSprintsVisualization,module,taiga;taiga=this.taiga,module=angular.module("taigaBacklog"),BacklogSprintDirective=function($repo,$rootscope){var link,refreshSprintTableHeight,slideOptions,sprintTableMinHeight,toggleSprint;return sprintTableMinHeight=50,slideOptions={duration:500,easing:"linear"},refreshSprintTableHeight=function(){return function(sprintTable){return sprintTable.find(".row").length?sprintTable.css("height","auto"):sprintTable.css("height",sprintTableMinHeight)}}(this),toggleSprint=function(){return function($el){var sprintArrow,sprintTable;return sprintTable=$el.find(".sprint-table"),sprintArrow=$el.find(".icon-arrow-up"),sprintArrow.toggleClass("active"),sprintTable.toggleClass("open"),refreshSprintTableHeight(sprintTable)}}(this),link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgBacklogSprint,function(sprint){return sprint=$scope.$eval($attrs.tgBacklogSprint),$scope.$first?toggleSprint($el):sprint.closed?$el.addClass("sprint-closed"):$scope.$first||sprint.closed?void 0:(toggleSprint($el),$el.addClass("sprint-old-open"))}),$el.on("click",".sprint-name > .icon-arrow-up",function(){return toggleSprint($el),$el.find(".sprint-table").slideToggle(slideOptions)}),$el.on("click",".sprint-name > .icon-edit",function(){var sprint;return sprint=$scope.$eval($attrs.tgBacklogSprint),$rootscope.$broadcast("sprintform:edit",sprint)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgBacklogSprint",["$tgRepo","$rootScope",BacklogSprintDirective]),BacklogSprintHeaderDirective=function($navUrls,$template){var link,template;return template=$template.get("backlog/sprint-header.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,isVisible,render;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_milestone")},isVisible=function(){return-1!==$scope.project.my_permissions.indexOf("view_milestones")},render=function(sprint){var ctx,estimatedDateRange,finish,start,taskboardUrl;return taskboardUrl=$navUrls.resolve("project-taskboard",{project:$scope.project.slug,sprint:sprint.slug}),start=moment(sprint.estimated_start).format("DD MMM YYYY"),finish=moment(sprint.estimated_finish).format("DD MMM YYYY"),estimatedDateRange=""+start+"-"+finish,ctx={name:sprint.name,taskboardUrl:taskboardUrl,estimatedDateRange:estimatedDateRange,closedPoints:sprint.closed_points||0,totalPoints:sprint.total_points||0,isVisible:isVisible(),isEditable:isEditable()},$el.html(template(ctx))},$scope.$watch($attrs.ngModel,function(sprint){return render(sprint)}),$scope.$on("sprintform:edit:success",function(){return render($model.$modelValue)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgBacklogSprintHeader",["$tgNavUrls","$tgTemplate",BacklogSprintHeaderDirective]),ToggleExcludeClosedSprintsVisualization=function($rootscope,$loading){var excludeClosedSprints,link;return excludeClosedSprints=!1,link=function($scope,$el){return $el.on("click","",function(){return $loading.start($el.siblings(".load")),$rootscope.$broadcast("backlog:toggle-closed-sprints-visualization")}),$scope.$on("$destroy",function(){return $el.off()}),$scope.$on("sprints:loaded",function(){return function(ctx,sprints){var closedSprints;return closedSprints=_.filter(sprints,function(sprint){return sprint.closed}),$loading.finish($el.siblings(".load")),$el.text(closedSprints.length>0?"Hide closed sprints":"Show closed sprints")}}(this))},{link:link}},module.directive("tgBacklogToggleClosedSprintsVisualization",["$rootScope","$tgLoading",ToggleExcludeClosedSprintsVisualization])}.call(this),function(){var SprintGraphDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,module=angular.module("taigaTaskboard"),SprintGraphDirective=function(){var link,redrawChart;return redrawChart=function(element,dataToDraw){var data,days,options,width;return width=element.width(),element.height(240),days=_.map(dataToDraw,function(x){return moment(x.day)}),data=[],data.unshift({data:_.zip(days,_.map(dataToDraw,function(d){return d.optimal_points})),lines:{fillColor:"rgba(120,120,120,0.2)"}}),data.unshift({data:_.zip(days,_.map(dataToDraw,function(d){return d.open_points})),lines:{fillColor:"rgba(102,153,51,0.3)"}}),options={grid:{borderWidth:{top:0,right:1,left:0,bottom:0},borderColor:"#ccc",hoverable:!0},xaxis:{tickSize:[1,"day"],min:days[0],max:_.last(days),mode:"time",daysNames:days,axisLabel:"Day",axisLabelUseCanvas:!0,axisLabelFontSizePixels:12,axisLabelFontFamily:"Verdana, Arial, Helvetica, Tahoma, sans-serif",axisLabelPadding:5},yaxis:{min:0},series:{shadowSize:0,lines:{show:!0,fill:!0},points:{show:!0,fill:!0,radius:4,lineWidth:2}},colors:["rgba(102,153,51,1)","rgba(120,120,120,0.2)"],tooltip:!0,tooltipOpts:{content:function(label,xval,yval,flotItem){var formattedDate,roundedValue;return formattedDate=moment(xval).format("DD MMM"),roundedValue=Math.round(yval),1===flotItem.seriesIndex?"Optimal pending points for day "+formattedDate+" should be "+roundedValue:"Real pending points for day "+formattedDate+" is "+roundedValue}}},element.empty(),element.plot(data,options).data("plot")},link=function($scope,$el){var element;return element=angular.element($el),$scope.$on("resize",function(){return $scope.stats?redrawChart(element,$scope.stats.days):void 0}),$scope.$on("taskboard:graph:toggle-visibility",function(){return $el.parent().toggleClass("open"),timeout(100,function(){return $scope.stats?redrawChart(element,$scope.stats.days):void 0})}),$scope.$watch("stats",function(){return null!=$scope.stats?redrawChart(element,$scope.stats.days):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgSprintGraph",SprintGraphDirective)}.call(this),function(){var CreateBulkTasksDirective,CreateEditTaskDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,CreateEditTaskDirective=function($repo,$model,$rs,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.isNew=!0,$scope.$on("taskform:new",function(ctx,sprintId,usId){return $scope.task={project:$scope.projectId,milestone:sprintId,user_story:usId,is_archived:!1,status:$scope.project.default_task_status,assigned_to:null,tags:[]},$scope.isNew=!0,$el.find(".button-green span").html("Create"),$el.find(".title").html("New task "),$el.find(".tag-input").val(""),lightboxService.open($el)}),$scope.$on("taskform:edit",function(ctx,task){return $scope.task=task,$scope.isNew=!1,$el.find(".button-green span").html("Save"),$el.find(".title").html("Edit task "),$el.find(".tag-input").val(""),lightboxService.open($el)}),submitButton=$el.find(".submit-button"),submit=debounce(2e3,function(){return function(event){var broadcastEvent,form,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($scope.isNew?(promise=$repo.create("tasks",$scope.task),broadcastEvent="taskform:new:success"):(promise=$repo.save($scope.task),broadcastEvent="taskform:edit:success"),$loading.start(submitButton),promise.then(function(data){return $loading.finish(submitButton),lightboxService.close($el),$rootscope.$broadcast(broadcastEvent,data)})):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},CreateBulkTasksDirective=function($repo,$rs,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.form={data:"",usId:null},submit=debounce(2e3,function(){return function(event){var data,form,projectId,promise,sprintId,usId;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),data=$scope.form.data,projectId=$scope.projectId,sprintId=$scope.form.sprintId,usId=$scope.form.usId,promise=$rs.tasks.bulkCreate(projectId,sprintId,usId,data),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("taskform:bulk:success",result),lightboxService.close($el)}),promise.then(null,function(){return $loading.finish(submitButton),console.log("FAIL")})):void 0}}(this)),$scope.$on("taskform:bulk",function(ctx,sprintId,usId){return lightboxService.open($el),$scope.form={data:"",sprintId:sprintId,usId:usId} +}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaTaskboard"),module.directive("tgLbCreateEditTask",["$tgRepo","$tgModel","$tgResources","$rootScope","$tgLoading","lightboxService",CreateEditTaskDirective]),module.directive("tgLbCreateBulkTasks",["$tgRepo","$tgResources","$rootScope","$tgLoading","lightboxService",CreateBulkTasksDirective])}.call(this),function(){var TaskboardController,TaskboardDirective,TaskboardSquishColumnDirective,TaskboardTableHeightFixerDirective,TaskboardTaskDirective,TaskboardUserDirective,bindMethods,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,toggleText=this.taiga.toggleText,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,scopeDefer=this.taiga.scopeDefer,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaTaskboard"),TaskboardController=function(_super){function TaskboardController(scope,rootscope,repo,confirm,rs,params,q,appTitle,location,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.appTitle=appTitle,this.location=location,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Taskboard",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Taskboard - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TaskboardController,_super),TaskboardController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$appTitle","$tgLocation","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],TaskboardController.prototype.initializeEventHandlers=function(){return this.scope.$on("taskform:bulk:success",function(_this){return function(){return _this.loadTaskboard(),_this.analytics.trackEvent("task","create","bulk create task on taskboard",1)}}(this)),this.scope.$on("taskform:new:success",function(_this){return function(){return _this.loadTaskboard(),_this.analytics.trackEvent("task","create","create task on taskboard",1)}}(this)),this.scope.$on("taskform:edit:success",function(_this){return function(){return _this.loadTaskboard()}}(this)),this.scope.$on("taskboard:task:move",this.taskMove),this.scope.$on("assigned-to:added",function(_this){return function(ctx,userId,task){var promise;return task.assigned_to=userId,promise=_this.repo.save(task),promise.then(null,function(){return console.log("FAIL")})}}(this))},TaskboardController.prototype.initializeSubscription=function(){var routingKey,routingKey1;return routingKey="changes.project."+this.scope.projectId+".tasks",this.events.subscribe(this.scope,routingKey,function(_this){return function(){return _this.loadTaskboard()}}(this)),routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.refreshTagsColors(),_this.loadSprintStats(),_this.loadSprint()}}(this))},TaskboardController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(e){return e.id}),_this.scope.roleById=groupBy(project.roles,function(e){return e.id}),_this.scope.taskStatusList=_.sortBy(project.task_statuses,"order"),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.scope.usStatusById=groupBy(project.us_statuses,function(e){return e.id}),_this.scope.$emit("project:loaded",project),project}}(this))},TaskboardController.prototype.loadSprintStats=function(){return this.rs.sprints.stats(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(stats){var completedPointsSum,remainingPointsSum,remainingTasks,totalPointsSum;return totalPointsSum=_.reduce(_.values(stats.total_points),function(res,n){return res+n},0),completedPointsSum=_.reduce(_.values(stats.completed_points),function(res,n){return res+n},0),remainingPointsSum=totalPointsSum-completedPointsSum,remainingTasks=stats.total_tasks-stats.completed_tasks,_this.scope.stats=stats,_this.scope.stats.totalPointsSum=totalPointsSum,_this.scope.stats.completedPointsSum=completedPointsSum,_this.scope.stats.remainingPointsSum=remainingPointsSum,_this.scope.stats.remainingTasks=remainingTasks,_this.scope.stats.completedPercentage=stats.totalPointsSum?Math.round(100*stats.completedPointsSum/stats.totalPointsSum):0,_this.scope.stats.openTasks=stats.total_tasks-stats.completed_tasks,stats}}(this))},TaskboardController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},TaskboardController.prototype.loadSprint=function(){return this.rs.sprints.get(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,_this.scope.userstories=_.sortBy(sprint.user_stories,"sprint_order"),sprint}}(this))},TaskboardController.prototype.loadTasks=function(){return this.rs.tasks.list(this.scope.projectId,this.scope.sprintId).then(function(_this){return function(tasks){var status,task,us,_i,_j,_k,_len,_len1,_len2,_ref,_ref1,_ref2;for(_this.scope.tasks=_.sortBy(tasks,"taskboard_order"),_this.scope.usTasks={},_ref=_.union(_this.scope.userstories,[{id:null}]),_i=0,_len=_ref.length;_len>_i;_i++)for(us=_ref[_i],_this.scope.usTasks[us.id]={},_ref1=_this.scope.taskStatusList,_j=0,_len1=_ref1.length;_len1>_j;_j++)status=_ref1[_j],_this.scope.usTasks[us.id][status.id]=[];for(_ref2=_this.scope.tasks,_k=0,_len2=_ref2.length;_len2>_k;_k++)task=_ref2[_k],null!=_this.scope.usTasks[task.user_story]&&null!=_this.scope.usTasks[task.user_story][task.status]&&_this.scope.usTasks[task.user_story][task.status].push(task);return tasks}}(this))},TaskboardController.prototype.loadTaskboard=function(){return this.q.all([this.refreshTagsColors(),this.loadSprintStats(),this.loadSprint().then(function(_this){return function(){return _this.loadTasks()}}(this))])},TaskboardController.prototype.loadInitialData=function(){var params,promise;return params={pslug:this.params.pslug,sslug:this.params.sslug},promise=this.repo.resolve(params).then(function(_this){return function(data){return _this.scope.projectId=data.project,_this.scope.sprintId=data.milestone,_this.initializeSubscription(),data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadTaskboard()}}(this))},TaskboardController.prototype.refreshTasksOrder=function(tasks){var data,items;return items=this.resortTasks(tasks),data=this.prepareBulkUpdateData(items),this.rs.tasks.bulkUpdateTaskTaskboardOrder(this.scope.project.id,data)},TaskboardController.prototype.resortTasks=function(tasks){var index,item,items,_i,_len;for(items=[],index=_i=0,_len=tasks.length;_len>_i;index=++_i)item=tasks[index],item.taskboard_order=index,item.isModified()&&items.push(item);return items},TaskboardController.prototype.prepareBulkUpdateData=function(uses){return _.map(uses,function(x){return{task_id:x.id,order:x.taskboard_order}})},TaskboardController.prototype.taskMove=function(ctx,task,usId,statusId,order){var promise,r,tasks;return r=this.scope.usTasks[task.user_story][task.status].indexOf(task),this.scope.usTasks[task.user_story][task.status].splice(r,1),tasks=this.scope.usTasks[usId][statusId],tasks.splice(order,0,task),task.user_story=usId,task.status=statusId,task.taskboard_order=order,promise=this.repo.save(task),this.rootscope.$broadcast("sprint:task:moved",task),promise.then(function(_this){return function(){return _this.refreshTasksOrder(tasks),_this.loadSprintStats()}}(this)),promise.then(null,function(){return function(){return console.log("FAIL TASK SAVE")}}(this))},TaskboardController.prototype.addNewTask=function(type,us){switch(type){case"standard":return this.rootscope.$broadcast("taskform:new",this.scope.sprintId,null!=us?us.id:void 0);case"bulk":return this.rootscope.$broadcast("taskform:bulk",this.scope.sprintId,null!=us?us.id:void 0)}},TaskboardController.prototype.editTaskAssignedTo=function(task){return this.rootscope.$broadcast("assigned-to:add",task)},TaskboardController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TaskboardController",TaskboardController),TaskboardDirective=function($rootscope){var link;return link=function($scope,$el){var $ctrl,tableBodyDom;return $ctrl=$el.controller(),$el.on("click",".toggle-analytics-visibility",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.toggleClass("active"),$rootscope.$broadcast("taskboard:graph:toggle-visibility")}),tableBodyDom=$el.find(".taskboard-table-body"),tableBodyDom.on("scroll",function(event){var tableHeaderDom,target;return target=angular.element(event.currentTarget),tableHeaderDom=$el.find(".taskboard-table-header .taskboard-table-inner"),tableHeaderDom.css("left",-1*target.scrollLeft())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgTaskboard",["$rootScope",TaskboardDirective]),TaskboardTaskDirective=function($rootscope){var link;return link=function($scope,$el){return $el.disableSelection(),$scope.$watch("task",function(task){return task.is_blocked&&!$el.hasClass("blocked")?$el.addClass("blocked"):!task.is_blocked&&$el.hasClass("blocked")?$el.removeClass("blocked"):void 0}),$el.find(".icon-edit").on("click",function(){return $el.find(".icon-edit").hasClass("noclick")?void 0:$scope.$apply(function(){return $rootscope.$broadcast("taskform:edit",$scope.task)})})},{link:link}},module.directive("tgTaskboardTask",["$rootScope",TaskboardTaskDirective]),TaskboardTableHeightFixerDirective=function(){var link,mainPadding,renderSize;return mainPadding=32,renderSize=function($el){var columnHeight,elementOffset,windowHeight;return elementOffset=$el.offset().top,windowHeight=angular.element(window).height(),columnHeight=windowHeight-elementOffset-mainPadding,$el.css("height",""+columnHeight+"px")},link=function($scope,$el){return timeout(500,function(){return renderSize($el)}),$scope.$on("resize",function(){return renderSize($el)})},{link:link}},module.directive("tgTaskboardTableHeightFixer",TaskboardTableHeightFixerDirective),TaskboardSquishColumnDirective=function(rs){var avatarWidth,link;return avatarWidth=40,link=function($scope,$el){var getCeilWidth,recalculateStatusColumnWidth,recalculateTaskboardWidth,refreshTaskboardTableWidth,setStatusColumnWidth;return $scope.$on("sprint:task:moved",function(){return function(){return recalculateTaskboardWidth()}}(this)),bindOnce($scope,"usTasks",function(){return $scope.statusesFolded=rs.tasks.getStatusColumnModes($scope.project.id),$scope.usFolded=rs.tasks.getUsRowModes($scope.project.id,$scope.sprintId),recalculateTaskboardWidth()}),$scope.foldStatus=function(status){return $scope.statusesFolded[status.id]=!$scope.statusesFolded[status.id],rs.tasks.storeStatusColumnModes($scope.projectId,$scope.statusesFolded),recalculateTaskboardWidth()},$scope.foldUs=function(us){return us?$scope.usFolded[us.id]=!$scope.usFolded[us.id]:$scope.usFolded[null]=!$scope.usFolded[null],rs.tasks.storeUsRowModes($scope.projectId,$scope.sprintId,$scope.usFolded),recalculateTaskboardWidth()},getCeilWidth=function(){return function(usId,statusId){var tasks,tasksMatrixSize,width;return tasks=$scope.usTasks[usId][statusId].length,$scope.statusesFolded[statusId]?(tasks&&$scope.usFolded[usId]?(tasksMatrixSize=Math.round(Math.sqrt(tasks)),width=avatarWidth*tasksMatrixSize):width=avatarWidth,width):0}}(this),setStatusColumnWidth=function(){return function(statusId,width){var column;return column=$el.find(".squish-status-"+statusId),width?column.css("max-width",width):column.css("max-width","none")}}(this),refreshTaskboardTableWidth=function(){return function(){var columnWidths,columns,totalWidth;return columnWidths=[],columns=$el.find(".task-colum-name"),columnWidths=_.map(columns,function(column){return $(column).outerWidth(!0)}),totalWidth=_.reduce(columnWidths,function(total,width){return total+width}),$el.find(".taskboard-table-inner").css("width",totalWidth)}}(this),recalculateStatusColumnWidth=function(){return function(statusId){var statusFoldedWidth;return statusFoldedWidth=getCeilWidth(null,statusId),_.forEach($scope.userstories,function(us){var width;return width=getCeilWidth(us.id,statusId),width>statusFoldedWidth?statusFoldedWidth=width:void 0}),setStatusColumnWidth(statusId,statusFoldedWidth)}}(this),recalculateTaskboardWidth=function(){return function(){_.forEach($scope.taskStatusList,function(status){return recalculateStatusColumnWidth(status.id)}),refreshTaskboardTableWidth()}}(this)},{link:link}},module.directive("tgTaskboardSquishColumn",["$tgResources",TaskboardSquishColumnDirective]),TaskboardUserDirective=function(){var clickable,link;return clickable=!1,link=function($scope,$el){var username_label;return username_label=$el.parent().find("a.task-assigned"),username_label.on("click",function(){var $ctrl;if(!$el.find("a").hasClass("noclick"))return $ctrl=$el.controller(),$ctrl.editTaskAssignedTo($scope.task)}),$scope.$watch("task.assigned_to",function(assigned_to){var user;return user=$scope.usersById[assigned_to],void 0===user?_.assign($scope,{name:"Unassigned",imgurl:"/images/unnamed.png",clickable:clickable}):_.assign($scope,{name:user.full_name_display,imgurl:user.photo,clickable:clickable}),username_label.text($scope.name)}),bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_task")>-1?(clickable=!0,$el.find(".avatar-assigned-to").on("click",function(){return function(){var $ctrl;if(!$el.find("a").hasClass("noclick"))return $ctrl=$el.controller(),$ctrl.editTaskAssignedTo($scope.task)}}(this))):void 0})},{link:link,template:"taskboard/taskboard-user.html",scope:{usersById:"=users",project:"=",task:"="}}},module.directive("tgTaskboardUserAvatar",["$log",TaskboardUserDirective])}.call(this),function(){var TaskboardSortableDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,module=angular.module("taigaBacklog"),TaskboardSortableDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){var deleteElement,itemEl,newParentScope,oldParentScope,tdom;return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el,deleteElement=function(itemEl){return itemEl.scope().$destroy(),itemEl.off(),itemEl.remove()},tdom.sortable({handle:".taskboard-task-inner",dropOnEmpty:!0,connectWith:".taskboard-tasks-box",revert:400}),tdom.on("sortstop",function(event,ui){var itemIndex,itemTask,newStatusId,newUsId,oldStatusId,oldUsId,parentEl;return parentEl=ui.item.parent(),itemEl=ui.item,itemTask=itemEl.scope().task,itemIndex=itemEl.index(),newParentScope=parentEl.scope(),oldUsId=oldParentScope.us?oldParentScope.us.id:null,oldStatusId=oldParentScope.st.id,newUsId=newParentScope.us?newParentScope.us.id:null,newStatusId=newParentScope.st.id,(newStatusId!==oldStatusId||newUsId!==oldUsId)&&deleteElement(itemEl),$scope.$apply(function(){return $rootscope.$broadcast("taskboard:task:move",itemTask,newUsId,newStatusId,itemIndex)}),ui.item.find("a").removeClass("noclick")}),tdom.on("sortstart",function(event,ui){return oldParentScope=ui.item.parent().scope(),ui.item.find("a").addClass("noclick")}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgTaskboardSortable",["$tgRepo","$tgResources","$rootScope",TaskboardSortableDirective])}.call(this),function(){var KanbanArchivedStatusHeaderDirective,KanbanArchivedStatusIntroDirective,KanbanColumnHeightFixerDirective,KanbanController,KanbanDirective,KanbanSquishColumnDirective,KanbanUserDirective,KanbanUserstoryDirective,KanbanWipLimitDirective,bindMethods,bindOnce,defaultViewMode,defaultViewModes,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,bindMethods=this.taiga.bindMethods,module=angular.module("taigaKanban"),defaultViewMode="maximized",defaultViewModes={maximized:{cardClass:"kanban-task-maximized"},minimized:{cardClass:"kanban-task-minimized"}},KanbanController=function(_super){function KanbanController(scope,rootscope,repo,confirm,rs,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,bindMethods(this),this.scope.sectionName="Kanban",this.scope.statusViewModes={},this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Kanban - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(KanbanController,_super),KanbanController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],KanbanController.prototype.initializeEventHandlers=function(){return this.scope.$on("usform:new:success",function(_this){return function(){return _this.loadUserstories(),_this.refreshTagsColors(),_this.analytics.trackEvent("userstory","create","create userstory on kanban",1)}}(this)),this.scope.$on("usform:bulk:success",function(_this){return function(){return _this.loadUserstories(),_this.analytics.trackEvent("userstory","create","bulk create userstory on kanban",1)}}(this)),this.scope.$on("usform:edit:success",function(_this){return function(){return _this.loadUserstories(),_this.refreshTagsColors()}}(this)),this.scope.$on("assigned-to:added",this.onAssignedToChanged),this.scope.$on("kanban:us:move",this.moveUs),this.scope.$on("kanban:show-userstories-for-status",this.loadUserStoriesForStatus),this.scope.$on("kanban:hide-userstories-for-status",this.hideUserStoriesForStatus)},KanbanController.prototype.addNewUs=function(type,statusId){switch(type){case"standard":return this.rootscope.$broadcast("usform:new",this.scope.projectId,statusId,this.scope.usStatusList);case"bulk":return this.rootscope.$broadcast("usform:bulk",this.scope.projectId,statusId)}},KanbanController.prototype.changeUsAssignedTo=function(us){return this.rootscope.$broadcast("assigned-to:add",us)},KanbanController.prototype.onAssignedToChanged=function(ctx,userid,us){var promise;return us.assigned_to=userid,promise=this.repo.save(us),promise.then(null,function(){return console.log("FAIL")})},KanbanController.prototype.refreshTagsColors=function(){return this.rs.projects.tagsColors(this.scope.projectId).then(function(_this){return function(tags_colors){return _this.scope.project.tags_colors=tags_colors}}(this))},KanbanController.prototype.loadUserstories=function(){var params;return params={status__is_archived:!1},this.rs.userstories.listAll(this.scope.projectId,params).then(function(_this){return function(userstories){var status,usByStatus,_i,_len,_ref;for(_this.scope.userstories=userstories,usByStatus=_.groupBy(userstories,"status"),_ref=_this.scope.usStatusList,_i=0,_len=_ref.length;_len>_i;_i++)status=_ref[_i],null==usByStatus[status.id]&&(usByStatus[status.id]=[]),status.is_archived&&null!=_this.scope.usByStatus&&(usByStatus[status.id]=_this.scope.usByStatus[status.id]),usByStatus[status.id]=_.sortBy(usByStatus[status.id],"kanban_order");return _this.scope.usByStatus=usByStatus,scopeDefer(_this.scope,function(){return _this.scope.$broadcast("userstories:loaded",userstories)}),userstories}}(this))},KanbanController.prototype.loadUserStoriesForStatus=function(ctx,statusId){var params;return params={status:statusId},this.rs.userstories.listAll(this.scope.projectId,params).then(function(_this){return function(userstories){return _this.scope.usByStatus[statusId]=_.sortBy(userstories,"kanban_order"),_this.scope.$broadcast("kanban:shown-userstories-for-status",statusId,userstories),userstories}}(this))},KanbanController.prototype.hideUserStoriesForStatus=function(ctx,statusId){return this.scope.usByStatus[statusId]=[],this.scope.$broadcast("kanban:hidden-userstories-for-status",statusId)},KanbanController.prototype.loadKanban=function(){return this.q.all([this.refreshTagsColors(),this.loadUserstories()])},KanbanController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.projectId=project.id,_this.scope.points=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(project.points,function(x){return x.id}),_this.scope.usStatusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.generateStatusViewModes(),_this.scope.$emit("project:loaded",project),project}}(this))},KanbanController.prototype.initializeSubscription=function(){var routingKey1;return routingKey1="changes.project."+this.scope.projectId+".userstories",this.events.subscribe(this.scope,routingKey1,function(_this){return function(){return _this.loadUserstories()}}(this))},KanbanController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription(),_this.loadKanban().then(function(){return _this.scope.$broadcast("redraw:wip")})}}(this))},KanbanController.prototype.generateStatusViewModes=function(){var mode,status,storedStatusViewModes,_i,_len,_ref;for(storedStatusViewModes=this.rs.kanban.getStatusViewModes(this.scope.projectId),this.scope.statusViewModes={},_ref=this.scope.usStatusList,_i=0,_len=_ref.length;_len>_i;_i++)status=_ref[_i],mode=storedStatusViewModes[status.id],this.scope.statusViewModes[status.id]=_.has(defaultViewModes,mode)?mode:defaultViewMode;return this.storeStatusViewModes()},KanbanController.prototype.storeStatusViewModes=function(){return this.rs.kanban.storeStatusViewModes(this.scope.projectId,this.scope.statusViewModes)},KanbanController.prototype.updateStatusViewMode=function(statusId,newViewMode){return this.scope.statusViewModes[statusId]=newViewMode,this.storeStatusViewModes()},KanbanController.prototype.getCardClass=function(statusId){var mode;return mode=this.scope.statusViewModes[statusId]||defaultViewMode,defaultViewModes[mode].cardClass||defaultViewModes[defaultViewMode].cardClass},KanbanController.prototype.prepareBulkUpdateData=function(uses,field){return null==field&&(field="kanban_order"),_.map(uses,function(x){return{us_id:x.id,order:x[field]}})},KanbanController.prototype.resortUserStories=function(uses){var index,item,items,_i,_len;for(items=[],index=_i=0,_len=uses.length;_len>_i;index=++_i)item=uses[index],item.kanban_order=index,item.isModified()&&items.push(item);return items},KanbanController.prototype.moveUs=function(ctx,us,oldStatusId,newStatusId,index){var itemsToSave,promise,r;return oldStatusId!==newStatusId?(r=this.scope.usByStatus[oldStatusId].indexOf(us),this.scope.usByStatus[oldStatusId].splice(r,1),this.scope.usByStatus[newStatusId].splice(index,0,us),us.status=newStatusId):(r=this.scope.usByStatus[newStatusId].indexOf(us),this.scope.usByStatus[newStatusId].splice(r,1),this.scope.usByStatus[newStatusId].splice(index,0,us)),itemsToSave=this.resortUserStories(this.scope.usByStatus[newStatusId]),this.scope.usByStatus[newStatusId]=_.sortBy(this.scope.usByStatus[newStatusId],"kanban_order"),promise=this.repo.save(us),promise=promise.then(function(_this){return function(){var data;return itemsToSave=_.reject(itemsToSave,{id:us.id}),data=_this.prepareBulkUpdateData(itemsToSave),_this.rs.userstories.bulkUpdateKanbanOrder(us.project,data).then(function(){return itemsToSave})}}(this))},KanbanController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("KanbanController",KanbanController),KanbanDirective=function(){var link;return link=function($scope,$el){var tableBodyDom;return tableBodyDom=$el.find(".kanban-table-body"),tableBodyDom.on("scroll",function(event){var tableHeaderDom,target;return target=angular.element(event.currentTarget),tableHeaderDom=$el.find(".kanban-table-header .kanban-table-inner"),tableHeaderDom.css("left",-1*target.scrollLeft())}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanban",["$tgRepo","$rootScope",KanbanDirective]),KanbanColumnHeightFixerDirective=function(){var link,mainPadding,renderSize,scrollPadding;return mainPadding=32,scrollPadding=0,renderSize=function($el){var columnHeight,elementOffset,windowHeight;return elementOffset=$el.parent().parent().offset().top,windowHeight=angular.element(window).height(),columnHeight=windowHeight-elementOffset-mainPadding-scrollPadding,$el.css("height",""+columnHeight+"px")},link=function($scope,$el){return timeout(500,function(){return renderSize($el)}),$scope.$on("resize",function(){return renderSize($el)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanColumnHeightFixer",KanbanColumnHeightFixerDirective),KanbanArchivedStatusHeaderDirective=function($rootscope){var hideArchivedText,link,showArchivedText;return showArchivedText="Show archived",hideArchivedText="Hide archived",link=function($scope,$el,$attrs){var hidden,status;return status=$scope.$eval($attrs.tgKanbanArchivedStatusHeader),hidden=!0,$scope["class"]="icon icon-open-eye",$scope.title=showArchivedText,$el.on("click",function(){return hidden=!hidden,$scope.$apply(function(){return hidden?($scope["class"]="icon icon-open-eye",$scope.title=showArchivedText,$rootscope.$broadcast("kanban:hide-userstories-for-status",status.id)):($scope["class"]="icon icon-closed-eye",$scope.title=hideArchivedText,$rootscope.$broadcast("kanban:show-userstories-for-status",status.id))})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanArchivedStatusHeader",["$rootScope",KanbanArchivedStatusHeaderDirective]),KanbanArchivedStatusIntroDirective=function(){var hiddenUserStoriexText,link,userStories;return hiddenUserStoriexText="The user stories in this status are hidden by default",userStories=[],link=function($scope,$el,$attrs){var status,updateIntroText;return status=$scope.$eval($attrs.tgKanbanArchivedStatusIntro),$el.text(hiddenUserStoriexText),updateIntroText=function(){return $el.text(userStories.length>0?"":hiddenUserStoriexText)},$scope.$on("kanban:us:move",function(ctx,itemUs,oldStatusId,newStatusId,itemIndex){var r;return status.id===newStatusId?status.id===oldStatusId?(r=userStories.indexOf(itemUs),userStories.splice(r,1),userStories.splice(itemIndex,0,itemUs)):(itemUs.isArchived=!0,userStories.splice(itemIndex,0,itemUs)):status.id===oldStatusId&&(itemUs.isArchived=!1,r=userStories.indexOf(itemUs),userStories.splice(r,1)),updateIntroText()}),$scope.$on("kanban:shown-userstories-for-status",function(ctx,statusId,userStoriesLoaded){return statusId===status.id?(userStories=_.filter(userStoriesLoaded,function(us){return us.status===status.id}),updateIntroText()):void 0}),$scope.$on("kanban:hidden-userstories-for-status",function(ctx,statusId){return statusId===status.id?(userStories=[],updateIntroText()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanArchivedStatusIntro",KanbanArchivedStatusIntroDirective),KanbanUserstoryDirective=function($rootscope){var link;return link=function($scope,$el,$attrs,$model){return $el.disableSelection(),$scope.$watch("us",function(us){return us.is_blocked&&!$el.hasClass("blocked")?$el.addClass("blocked"):!us.is_blocked&&$el.hasClass("blocked")?$el.removeClass("blocked"):void 0}),$el.find(".icon-edit").on("click",function(){return $el.find(".icon-edit").hasClass("noclick")?void 0:$scope.$apply(function(){return $rootscope.$broadcast("usform:edit",$model.$modelValue)})}),$scope.$on("$destroy",function(){return $el.off()})},{templateUrl:"kanban/kanban-task.html",link:link,require:"ngModel"}},module.directive("tgKanbanUserstory",["$rootScope",KanbanUserstoryDirective]),KanbanSquishColumnDirective=function(rs){var link;return link=function($scope,$el){var updateTableWidth;return $scope.$on("project:loaded",function(event,project){return $scope.folds=rs.kanban.getStatusColumnModes(project.id),updateTableWidth()}),$scope.foldStatus=function(status){$scope.folds[status.id]=!$scope.folds[status.id],rs.kanban.storeStatusColumnModes($scope.projectId,$scope.folds),updateTableWidth()},updateTableWidth=function(){var columnWidths,totalWidth;return columnWidths=_.map($scope.usStatusList,function(status){return $scope.folds[status.id]?40:310}),totalWidth=_.reduce(columnWidths,function(total,width){return total+width}),$el.find(".kanban-table-inner").css("width",totalWidth)}},{link:link}},module.directive("tgKanbanSquishColumn",["$tgResources",KanbanSquishColumnDirective]),KanbanWipLimitDirective=function(){var link;return link=function($scope,$el,$attrs){var redrawWipLimit;return $el.disableSelection(),redrawWipLimit=function(){return $el.find(".kanban-wip-limit").remove(),timeout(200,function(){var element;return element=$el.find(".kanban-task")[$scope.$eval($attrs.tgKanbanWipLimit)],element?angular.element(element).before("
    "):void 0})},$scope.$on("redraw:wip",redrawWipLimit),$scope.$on("kanban:us:move",redrawWipLimit),$scope.$on("usform:new:success",redrawWipLimit),$scope.$on("usform:bulk:success",redrawWipLimit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanWipLimit",KanbanWipLimitDirective),KanbanUserDirective=function($log){var clickable,link,template;return template=_.template('
    \n class="not-clickable"<% } %>>\n <%- name %>\n \n
    '),clickable=!1,link=function($scope,$el,$attrs,$model){var render,wtid;return $attrs.tgKanbanUserAvatar?(wtid=$scope.$watch($attrs.tgKanbanUserAvatar,function(v){var user;return null==$scope.usersById?($log.error("KanbanUserDirective requires userById set in scope."),wtid()):(user=$scope.usersById[v],render(user))}),render=function(user){var ctx,html,username_label;return ctx=void 0===user?{name:"Unassigned",imgurl:"/images/unnamed.png",clickable:clickable}:{name:user.full_name_display,imgurl:user.photo,clickable:clickable},html=template(ctx),$el.html(html),username_label=$el.parent().find("a.task-assigned"),username_label.html(ctx.name),username_label.on("click",function(){var $ctrl,us; +if(!$el.find("a").hasClass("noclick"))return us=$model.$modelValue,$ctrl=$el.controller(),$ctrl.changeUsAssignedTo(us)})},bindOnce($scope,"project",function(project){return project.my_permissions.indexOf("modify_us")>-1?(clickable=!0,$el.on("click",function(){return function(){var $ctrl,us;if(!$el.find("a").hasClass("noclick"))return us=$model.$modelValue,$ctrl=$el.controller(),$ctrl.changeUsAssignedTo(us)}}(this))):void 0}),$scope.$on("$destroy",function(){return $el.off()})):$log.error("KanbanUserDirective: no attr is defined")},{link:link,require:"ngModel"}},module.directive("tgKanbanUserAvatar",["$log",KanbanUserDirective])}.call(this),function(){var KanbanSortableDirective,bindOnce,groupBy,mixOf,module,scopeDefer,taiga,timeout,toggleText;taiga=this.taiga,mixOf=this.taiga.mixOf,toggleText=this.taiga.toggleText,scopeDefer=this.taiga.scopeDefer,bindOnce=this.taiga.bindOnce,groupBy=this.taiga.groupBy,timeout=this.taiga.timeout,module=angular.module("taigaKanban"),KanbanSortableDirective=function($repo,$rs,$rootscope){var link;return link=function($scope,$el){return bindOnce($scope,"project",function(project){var deleteElement,itemEl,newParentScope,oldParentScope,tdom;if(project.my_permissions.indexOf("modify_us")>-1)return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el,deleteElement=function(itemEl){return itemEl.scope().$destroy(),itemEl.off(),itemEl.remove()},tdom.sortable({handle:".kanban-task-inner",dropOnEmpty:!0,connectWith:".kanban-uses-box",revert:400}),tdom.on("sortstop",function(event,ui){var itemIndex,itemUs,newStatusId,oldStatusId,parentEl;return parentEl=ui.item.parent(),itemEl=ui.item,itemUs=itemEl.scope().us,itemIndex=itemEl.index(),newParentScope=parentEl.scope(),newStatusId=newParentScope.s.id,oldStatusId=oldParentScope.s.id,newStatusId!==oldStatusId&&deleteElement(itemEl),$scope.$apply(function(){return $rootscope.$broadcast("kanban:us:move",itemUs,itemUs.status,newStatusId,itemIndex)}),ui.item.find("a").removeClass("noclick")}),tdom.on("sortstart",function(event,ui){return oldParentScope=ui.item.parent().scope(),ui.item.find("a").addClass("noclick")})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgKanbanSortable",["$tgRepo","$tgResources","$rootScope",KanbanSortableDirective])}.call(this),function(){var IssueDetailController,IssuePriorityButtonDirective,IssueSeverityButtonDirective,IssueStatusButtonDirective,IssueStatusDisplayDirective,IssueTypeButtonDirective,PromoteIssueToUsButtonDirective,bindOnce,groupBy,joinStr,mixOf,module,taiga,toString,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaIssues"),IssueDetailController=function(_super){function IssueDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,analytics,navUrls,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.analytics=analytics,this.navUrls=navUrls,this.scope.issueRef=this.params.issueref,this.scope.sectionName="Issue Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.issue.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(IssueDetailController,_super),IssueDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgAnalytics","$tgNavUrls","tgLoader"],IssueDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("attachment:create",function(_this){return function(){return _this.rootscope.$broadcast("history:reload"),_this.analytics.trackEvent("attachment","create","create attachment on issue",1)}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("promote-issue-to-us:success",function(_this){return function(){return _this.analytics.trackEvent("issue","promoteToUserstory","promote issue to userstory",1),_this.rootscope.$broadcast("history:reload"),_this.loadIssue()}}(this))},IssueDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;return ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.scope.project.is_issues_activated?this.navUrls.resolve("project-issues",ctx):this.navUrls.resolve("project",ctx)},IssueDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.issue_statuses,_this.scope.statusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.typeById=groupBy(project.issue_types,function(x){return x.id}),_this.scope.typeList=_.sortBy(project.issue_types,"order"),_this.scope.severityList=project.severities,_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.priorityList=project.priorities,_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},IssueDetailController.prototype.loadIssue=function(){return this.rs.issues.getByRef(this.scope.projectId,this.params.issueref).then(function(_this){return function(issue){var ctx;return _this.scope.issue=issue,_this.scope.issueId=issue.id,_this.scope.commentModel=issue,null!=_this.scope.issue.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.issue.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-issues-detail",ctx)),null!=_this.scope.issue.neighbors.next.ref?(ctx={project:_this.scope.project.slug,ref:_this.scope.issue.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-issues-detail",ctx)):void 0}}(this))},IssueDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadIssue()}}(this))},IssueDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("IssueDetailController",IssueDetailController),IssueStatusDisplayDirective=function($template){var link,template;return template=$template.get("common/components/status-display.html",!0),link=function($scope,$el,$attrs){var render;return render=function(issue){var html;return html=template({status:$scope.statusById[issue.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(issue){return null!=issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueStatusDisplay",["$tgTemplate",IssueStatusDisplayDirective]),IssueStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("issue/issues-status-button.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,status;return status=$scope.statusById[issue.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(value,issue){var onError,onSuccess;return onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save(value).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var issue,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),$.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.status=target.data("status-id"),$model.$setViewValue(issue),save($model.$modelValue,issue)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",IssueStatusButtonDirective]),IssueTypeButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("issue/issue-type-button.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,type;return type=$scope.typeById[issue.type],html=template({type:type,typees:$scope.typeList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(type){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.type=type,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".type-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-type").popover().open():void 0}),$el.on("click",".type",function(event){var target,type;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),type=target.data("type-id"),save(type)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueTypeButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",IssueTypeButtonDirective]),IssueSeverityButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("issue/issue-severity-button.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,severity;return severity=$scope.severityById[issue.severity],html=template({severity:severity,severityes:$scope.severityList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(severity){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.severity=severity,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".severity-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-severity").popover().open():void 0}),$el.on("click",".severity",function(event){var severity,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),severity=target.data("severity-id"),save(severity)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssueSeverityButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",IssueSeverityButtonDirective]),IssuePriorityButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("issue/issue-priority-button.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_issue")},render=function(){return function(issue){var html,priority;return priority=$scope.priorityById[issue.priority],html=template({priority:priority,priorityes:$scope.priorityList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(priority){var issue,onError,onSuccess;return $.fn.popover().closeAll(),issue=$model.$modelValue.clone(),issue.priority=priority,$model.$setViewValue(issue),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),issue.revert(),$model.$setViewValue(issue),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".priority-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-priority").popover().open():void 0}),$el.on("click",".priority",function(event){var priority,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),priority=target.data("priority-id"),save(priority)):void 0}),$scope.$watch($attrs.ngModel,function(issue){return issue?render(issue):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgIssuePriorityButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",IssuePriorityButtonDirective]),PromoteIssueToUsButtonDirective=function($rootScope,$repo,$confirm,$qqueue){var link;return link=function($scope,$el,$attrs,$model){var save;return save=$qqueue.bindAdd(function(){return function(issue,finish){var data,onError,onSuccess;return data={generated_from_issue:issue.id,project:issue.project,subject:issue.subject,description:issue.description,tags:issue.tags,is_blocked:issue.is_blocked,blocked_note:issue.blocked_note},onSuccess=function(){return finish(),$confirm.notify("success"),$rootScope.$broadcast("promote-issue-to-us:success")},onError=function(){return finish(!1),$confirm.notify("error")},$repo.create("userstories",data).then(onSuccess,onError)}}(this)),$el.on("click","a",function(event){var issue,message,subtitle,title;return event.preventDefault(),issue=$model.$modelValue,title="Promote this issue to a new user story",message="Are you sure you want to create a new US from this Issue?",subtitle=issue.subject,$confirm.ask(title,subtitle,message).then(function(){return function(finish){return save(issue,finish)}}(this))}),$scope.$on("$destroy",function(){return $el.off()})},{restrict:"AE",require:"ngModel",templateUrl:"issue/promote-issue-to-us-button.html",link:link}},module.directive("tgPromoteIssueToUsButton",["$rootScope","$tgRepo","$tgConfirm","$tgQqueue",PromoteIssueToUsButtonDirective])}.call(this),function(){var CreateBulkIssuesDirective,CreateIssueDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaIssues"),CreateIssueDirective=function($repo,$confirm,$rootscope,lightboxService,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley(),$scope.issue={},$scope.$on("issueform:new",function(ctx,project){return $el.find(".tag-input").val(""),lightboxService.open($el),$scope.issue={project:project.id,subject:"",status:project.default_issue_status,type:project.default_issue_type,priority:project.default_priority,severity:project.default_severity,tags:[]}}),$scope.$on("$destroy",function(){return $el.off()}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("issues",$scope.issue),promise.then(function(data){return $loading.finish(submitButton),$rootscope.$broadcast("issueform:new:success",data),lightboxService.close($el),$confirm.notify("success")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLbCreateIssue",["$tgRepo","$tgConfirm","$rootScope","lightboxService","$tgLoading",CreateIssueDirective]),CreateBulkIssuesDirective=function($repo,$rs,$confirm,$rootscope,$loading,lightboxService){var link;return link=function($scope,$el){var submit,submitButton;return $scope.$on("issueform:bulk",function(ctx,projectId){return lightboxService.open($el),$scope["new"]={projectId:projectId,bulk:""}}),submit=debounce(2e3,function(){return function(event){var data,form,projectId,promise;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?($loading.start(submitButton),data=$scope["new"].bulk,projectId=$scope["new"].projectId,promise=$rs.issues.bulkCreate(projectId,data),promise.then(function(result){return $loading.finish(submitButton),$rootscope.$broadcast("issueform:new:success",result),lightboxService.close($el),$confirm.notify("success")}),promise.then(null,function(){return $loading.finish(submitButton),$confirm.notify("error")})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgLbCreateBulkIssues",["$tgRepo","$tgResources","$tgConfirm","$rootScope","$tgLoading","lightboxService",CreateBulkIssuesDirective])}.call(this),function(){var IssueAssignedToInlineEditionDirective,IssueStatusInlineEditionDirective,IssuesController,IssuesDirective,IssuesFiltersDirective,bindOnce,debounceLeading,groupBy,joinStr,mixOf,module,startswith,taiga,toString,trim,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounceLeading=this.taiga.debounceLeading,startswith=this.taiga.startswith,module=angular.module("taigaIssues"),IssuesController=function(_super){function IssuesController(scope,rootscope,repo,confirm,rs,urls,params,q,location,appTitle,navUrls,events,analytics,tgLoader){var filters,promise;return this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.urls=urls,this.params=params,this.q=q,this.location=location,this.appTitle=appTitle,this.navUrls=navUrls,this.events=events,this.analytics=analytics,this.loadIssues=__bind(this.loadIssues,this),this.scope.sectionName="Issues",this.scope.filters={},_.isEmpty(this.location.search())?(filters=this.rs.issues.getFilters(this.params.pslug),filters.page=1,this.location.search(filters),void this.location.replace()):(promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Issues - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded),void this.scope.$on("issueform:new:success",function(_this){return function(){return _this.analytics.trackEvent("issue","create","create issue on issues list",1),_this.loadIssues(),_this.loadFilters()}}(this)))}return __extends(IssuesController,_super),IssuesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$tgUrls","$routeParams","$q","$tgLocation","$appTitle","$tgNavUrls","$tgEvents","$tgAnalytics","tgLoader"],IssuesController.prototype.initializeSubscription=function(){var routingKey;return routingKey="changes.project."+this.scope.projectId+".issues",this.events.subscribe(this.scope,routingKey,function(_this){return function(){return _this.loadIssues()}}(this))},IssuesController.prototype.storeFilters=function(){return this.rs.issues.storeFilters(this.params.pslug,this.location.search())},IssuesController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issueStatusById=groupBy(project.issue_statuses,function(x){return x.id}),_this.scope.issueStatusList=_.sortBy(project.issue_statuses,"order"),_this.scope.severityById=groupBy(project.severities,function(x){return x.id}),_this.scope.severityList=_.sortBy(project.severities,"order"),_this.scope.priorityById=groupBy(project.priorities,function(x){return x.id}),_this.scope.priorityList=_.sortBy(project.priorities,"order"),_this.scope.issueTypes=_.sortBy(project.issue_types,"order"),_this.scope.issueTypeById=groupBy(project.issue_types,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},IssuesController.prototype.getUrlFilters=function(){var filters;return filters=_.pick(this.location.search(),"page","tags","statuses","types","q","severities","priorities","assignedTo","createdBy","orderBy"),filters.page||(filters.page=1),filters},IssuesController.prototype.getUrlFilter=function(name){var filters;return filters=_.pick(this.location.search(),name),filters[name]},IssuesController.prototype.loadMyFilters=function(){return this.rs.issues.getMyFilters(this.scope.projectId).then(function(){return function(filters){return _.map(filters,function(value,key){return{id:key,name:key,type:"myFilters",selected:!1}})}}(this))},IssuesController.prototype.removeNotExistingFiltersFromUrl=function(){var currentSearch,existingValues,filterName,filterValue,splittedValues,urlfilters;currentSearch=this.location.search(),urlfilters=this.getUrlFilters();for(filterName in urlfilters)filterValue=urlfilters[filterName],"page"!==filterName&&"orderBy"!==filterName&&"q"!==filterName&&(splittedValues="tags"===filterName?_.map((""+filterValue).split(",")):_.map((""+filterValue).split(","),function(x){return"null"===x?null:parseInt(x)}),existingValues=_.intersection(splittedValues,_.map(this.scope.filters[filterName],"id")),splittedValues.length!==existingValues.length&&this.location.search(filterName,existingValues.join()));return currentSearch!==this.location.search()?this.location.replace():void 0},IssuesController.prototype.markSelectedFilters=function(filters,urlfilters){var isSelected,key,name,obj,searchdata,val,value,_i,_len,_ref,_ref1,_results;searchdata={},_ref=_.omit(urlfilters,"page","orderBy");for(name in _ref)for(value=_ref[name],null==searchdata[name]&&(searchdata[name]={}),_ref1=(""+value).split(","),_i=0,_len=_ref1.length;_len>_i;_i++)val=_ref1[_i],searchdata[name][val]=!0;isSelected=function(type,id){return null!=searchdata[type]&&searchdata[type][id]?!0:!1},_results=[];for(key in filters)value=filters[key],_results.push(function(){var _j,_len1,_results1;for(_results1=[],_j=0,_len1=value.length;_len1>_j;_j++)obj=value[_j],_results1.push(obj.selected=isSelected(obj.type,obj.id)?!0:void 0);return _results1}());return _results},IssuesController.prototype.loadFilters=function(){var promise,urlfilters;return urlfilters=this.getUrlFilters(),urlfilters.q&&(this.scope.filtersQ=urlfilters.q),promise=this.loadMyFilters().then(function(_this){return function(myFilters){return _this.scope.filters.myFilters=myFilters,myFilters}}(this)),promise=promise.then(function(_this){return function(){return _this.rs.issues.filtersData(_this.scope.projectId)}}(this)),promise.then(function(_this){return function(data){var choicesFiltersFormat,tagsFilterFormat,usersFiltersFormat;return usersFiltersFormat=function(users,type,unknownOption){var reformatedUsers,unknownItem;return reformatedUsers=_.map(users,function(t){return{id:t[0],count:t[1],type:type,name:t[0]?_this.scope.usersById[t[0]].full_name_display:unknownOption}}),unknownItem=_.remove(reformatedUsers,function(u){return!u.id}),reformatedUsers=_.sortBy(reformatedUsers,function(u){return u.name.toUpperCase()}),unknownItem.length>0&&reformatedUsers.unshift(unknownItem[0]),reformatedUsers},choicesFiltersFormat=function(choices,type,byIdObject){return _.map(choices,function(t){return{id:t[0],name:byIdObject[t[0]].name,color:byIdObject[t[0]].color,count:t[1],type:type}})},tagsFilterFormat=function(tags){return _.map(tags,function(t){return{id:t[0],name:t[0],color:_this.scope.project.tags_colors[t[0]],count:t[1],type:"tags"}})},_this.scope.filters.statuses=choicesFiltersFormat(data.statuses,"statuses",_this.scope.issueStatusById),_this.scope.filters.severities=choicesFiltersFormat(data.severities,"severities",_this.scope.severityById),_this.scope.filters.priorities=choicesFiltersFormat(data.priorities,"priorities",_this.scope.priorityById),_this.scope.filters.assignedTo=usersFiltersFormat(data.assigned_to,"assignedTo","Unassigned"),_this.scope.filters.createdBy=usersFiltersFormat(data.created_by,"createdBy","Unknown"),_this.scope.filters.types=choicesFiltersFormat(data.types,"types",_this.scope.issueTypeById),_this.scope.filters.tags=tagsFilterFormat(data.tags),_this.removeNotExistingFiltersFromUrl(),_this.markSelectedFilters(_this.scope.filters,urlfilters),_this.rootscope.$broadcast("filters:loaded",_this.scope.filters)}}(this))},IssuesController.prototype.loadIssuesRequests=0,IssuesController.prototype.loadIssues=function(){var name,promise,values,_ref;this.scope.urlFilters=this.getUrlFilters(),this.scope.httpParams={},_ref=this.scope.urlFilters;for(name in _ref)values=_ref[name],"severities"===name?name="severity":"orderBy"===name?name="order_by":"priorities"===name?name="priority":"assignedTo"===name?name="assigned_to":"createdBy"===name?name="owner":"statuses"===name?name="status":"types"===name&&(name="type"),this.scope.httpParams[name]=values;return promise=this.rs.issues.list(this.scope.projectId,this.scope.httpParams),this.loadIssuesRequests+=1,promise.index=this.loadIssuesRequests,promise.then(function(_this){return function(data){return promise.index===_this.loadIssuesRequests&&(_this.scope.issues=data.models,_this.scope.page=data.current,_this.scope.count=data.count,_this.scope.paginatedBy=data.paginatedBy),data}}(this))},IssuesController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.initializeSubscription(),_this.q.all([_this.loadFilters(),_this.loadIssues()])}}(this))},IssuesController.prototype.saveCurrentFiltersTo=function(newFilter){var deferred;return deferred=this.q.defer(),this.rs.issues.getMyFilters(this.scope.projectId).then(function(_this){return function(filters){return filters[newFilter]=_this.location.search(),_this.rs.issues.storeMyFilters(_this.scope.projectId,filters).then(function(){return deferred.resolve()})}}(this)),deferred.promise},IssuesController.prototype.deleteMyFilter=function(filter){var deferred;return deferred=this.q.defer(),this.rs.issues.getMyFilters(this.scope.projectId).then(function(_this){return function(filters){return delete filters[filter],_this.rs.issues.storeMyFilters(_this.scope.projectId,filters).then(function(){return deferred.resolve()})}}(this)),deferred.promise},IssuesController.prototype.addNewIssue=function(){return this.rootscope.$broadcast("issueform:new",this.scope.project)},IssuesController.prototype.addIssuesInBulk=function(){return this.rootscope.$broadcast("issueform:bulk",this.scope.projectId)},IssuesController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("IssuesController",IssuesController),IssuesDirective=function($log,$location,$template){var link,linkOrdering,linkPagination,template;return template=$template.get("issue/issue-paginator.html",!0),linkPagination=function($scope,$el,$attrs,$ctrl){var $pagEl,afterCurrent,atBegin,atEnd,beforeCurrent,getNumPages,renderPagination;return afterCurrent=2,beforeCurrent=4,atBegin=2,atEnd=2,$pagEl=$el.find(".issues-paginator"),getNumPages=function(){var numPages;return numPages=$scope.count/$scope.paginatedBy,numPages=parseInt(numPages,10)=numPages)return void $pagEl.hide();for($pagEl.show(),pages=[],options={},options.pages=pages,options.showPrevious=$scope.page>1,options.showNext=!($scope.page===numPages),cpage=$scope.page,i=_i=1;numPages>=1?numPages>=_i:_i>=numPages;i=numPages>=1?++_i:--_i)i===cpage+afterCurrent&&numPages>cpage+afterCurrent+atEnd?pages.push({classes:"dots",type:"dots"}):i===cpage-beforeCurrent&&cpage>atBegin+beforeCurrent?pages.push({classes:"dots",type:"dots"}):i>cpage+afterCurrent&&numPages-atEnd>=i||cpage-beforeCurrent>i&&i>atBegin||pages.push(i===cpage?{classes:"active",num:i,type:"page-active"}:{classes:"page",num:i,type:"page"});return $pagEl.html(template(options))},$scope.$watch("issues",function(value){return value?renderPagination():void 0}),$el.on("click",".issues-paginator a.next",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page+1),$ctrl.loadIssues()})}),$el.on("click",".issues-paginator a.previous",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page-1),$ctrl.loadIssues()})}),$el.on("click",".issues-paginator li.page > a",function(event){var pagenum,target;return event.preventDefault(),target=angular.element(event.currentTarget),pagenum=target.data("pagenum"),$scope.$apply(function(){return $ctrl.selectFilter("page",pagenum),$ctrl.loadIssues()})})},linkOrdering=function($scope,$el,$attrs,$ctrl){var colHeadElement,currentOrder,icon;return currentOrder=$ctrl.getUrlFilter("orderBy")||"created_date",currentOrder&&(icon=startswith(currentOrder,"-")?"icon-caret-up":"icon-caret-down",colHeadElement=$el.find(".row.title > div[data-fieldname='"+trim(currentOrder,"-")+"']"),colHeadElement.html(""+colHeadElement.html()+"")),$el.on("click",".row.title > div",function(event){var finalOrder,newOrder,target;return target=angular.element(event.currentTarget),currentOrder=$ctrl.getUrlFilter("orderBy"),newOrder=target.data("fieldname"),finalOrder=currentOrder===newOrder?"-"+newOrder:newOrder,$scope.$apply(function(){return $ctrl.replaceFilter("orderBy",finalOrder),$ctrl.storeFilters(),$ctrl.loadIssues().then(function(){return $el.find(".row.title > div > span.icon").remove(),icon=startswith(finalOrder,"-")?"icon-caret-up":"icon-caret-down",target.html(""+target.html()+"") +})})})},link=function($scope,$el,$attrs){var $ctrl;return $ctrl=$el.controller(),linkOrdering($scope,$el,$attrs,$ctrl),linkPagination($scope,$el,$attrs,$ctrl),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssues",["$log","$tgLocation","$tgTemplate",IssuesDirective]),IssuesFiltersDirective=function($log,$location,$rs,$confirm,$loading,$template){var link,template,templateSelected;return template=$template.get("issue/issues-filters.html",!0),templateSelected=$template.get("issue/issues-filters-selected.html",!0),link=function($scope,$el){var $ctrl,initializeSelectedFilters,renderFilters,renderSelectedFilters,selectQFilter,selectedFilters,showCategories,showFilters,toggleFilterSelection;return $ctrl=$el.closest(".wrapper").controller(),selectedFilters=[],showFilters=function(title,type){return $el.find(".filters-cats").hide(),$el.find(".filter-list").removeClass("hidden"),$el.find("h2.breadcrumb").removeClass("hidden"),$el.find("h2 a.subfilter span.title").html(title),$el.find("h2 a.subfilter span.title").prop("data-type",type)},showCategories=function(){return $el.find(".filters-cats").show(),$el.find(".filter-list").addClass("hidden"),$el.find("h2.breadcrumb").addClass("hidden")},initializeSelectedFilters=function(filters){var name,val,values,_i,_len;selectedFilters=[];for(name in filters)for(values=filters[name],_i=0,_len=values.length;_len>_i;_i++)val=values[_i],val.selected&&selectedFilters.push(val);return renderSelectedFilters(selectedFilters)},renderSelectedFilters=function(selectedFilters){var html;return _.filter(selectedFilters,function(){return function(f){return f.color?f.style="border-left: 3px solid "+f.color:void 0}}(this)),html=templateSelected({filters:selectedFilters}),$el.find(".filters-applied").html(html),selectedFilters.length>0?$el.find(".save-filters").show():$el.find(".save-filters").hide()},renderFilters=function(filters){var html;return _.filter(filters,function(){return function(f){return f.color?f.style="border-left: 3px solid "+f.color:void 0}}(this)),html=template({filters:filters}),$el.find(".filter-list").html(html)},toggleFilterSelection=function(type,id){var currentFiltersType,filter,filterId,filters;return"myFilters"===type?($rs.issues.getMyFilters($scope.projectId).then(function(data){var filters,myFilters;return myFilters=data,filters=myFilters[id],filters.page=1,$ctrl.replaceAllFilters(filters),$ctrl.storeFilters(),$ctrl.loadIssues(),$ctrl.markSelectedFilters($scope.filters,filters),initializeSelectedFilters($scope.filters)}),null):(filters=$scope.filters[type],filterId="tags"===type?taiga.toString(id):id,filter=_.find(filters,{id:filterId}),filter.selected=!filter.selected,null===id&&(id="null"),filter.selected?(selectedFilters.push(filter),$scope.$apply(function(){return $ctrl.selectFilter(type,id),$ctrl.selectFilter("page",1),$ctrl.storeFilters(),$ctrl.loadIssues()})):(selectedFilters=_.reject(selectedFilters,filter),$scope.$apply(function(){return $ctrl.unselectFilter(type,id),$ctrl.selectFilter("page",1),$ctrl.storeFilters(),$ctrl.loadIssues()})),renderSelectedFilters(selectedFilters),currentFiltersType=$el.find("h2 a.subfilter span.title").prop("data-type"),type===currentFiltersType?renderFilters(_.reject(filters,"selected")):void 0)},$scope.$on("filters:loaded",function(ctx,filters){return initializeSelectedFilters(filters)}),selectQFilter=debounceLeading(100,function(value){return void 0!==value?(0===value.length?($ctrl.replaceFilter("q",null),$ctrl.storeFilters()):($ctrl.replaceFilter("q",value),$ctrl.storeFilters()),$ctrl.loadIssues()):void 0}),$scope.$watch("filtersQ",selectQFilter),$el.on("click",".filters-cats > ul > li > a",function(event){var tags,target;return event.preventDefault(),target=angular.element(event.currentTarget),tags=$scope.filters[target.data("type")],renderFilters(_.reject(tags,"selected")),showFilters(target.attr("title"),target.data("type"))}),$el.on("click",".filters-inner > .filters-step-cat > .breadcrumb > .back",function(event){return event.preventDefault(),showCategories($el)}),$el.on("click",".filters-applied a",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),id=target.data("id")||null,type=target.data("type"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter",function(event){var id,target,type;return event.preventDefault(),target=angular.element(event.currentTarget),target.toggleClass("active"),id=target.data("id")||null,type=target.data("type"),"myFilters"===type&&target.removeClass("active"),toggleFilterSelection(type,id)}),$el.on("click",".filter-list .single-filter .icon-delete",function(event){var customFilterName,message,target,title;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),customFilterName=target.parent().data("id"),title="Delete custom filter",message="the custom filter '"+customFilterName+"'",$confirm.askOnDelete(title,message).then(function(finish){var promise;return promise=$ctrl.deleteMyFilter(customFilterName),promise.then(function(){return promise=$ctrl.loadMyFilters(),promise.then(function(filters){return finish(),$scope.filters.myFilters=filters,renderFilters($scope.filters.myFilters)}),promise.then(null,function(){return finish()})}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})})}),$el.on("click",".save-filters",function(event){return event.preventDefault(),renderFilters($scope.filters.myFilters),showFilters("My filters","myFilters"),$el.find(".save-filters").hide(),$el.find(".my-filter-name").removeClass("hidden"),$el.find(".my-filter-name").focus()}),$el.on("keyup",".new .my-filter-name",function(event){var newFilter,promise,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newFilter=target.val(),$loading.start($el.find(".new")),promise=$ctrl.saveCurrentFiltersTo(newFilter),promise.then(function(){var loadPromise;return loadPromise=$ctrl.loadMyFilters(),loadPromise.then(function(filters){var currentfilterstype;return $loading.finish($el.find(".new")),$scope.filters.myFilters=filters,currentfilterstype=$el.find("h2 a.subfilter span.title").prop("data-type"),"myFilters"===currentfilterstype&&renderFilters($scope.filters.myFilters),$el.find(".my-filter-name").addClass("hidden"),$el.find(".save-filters").show()}),loadPromise.then(null,function(){return $loading.finish($el.find(".new")),$confirm.notify("error","Error loading custom filters")})}),promise.then(null,function(){return $loading.finish($el.find(".new")),$el.find(".my-filter-name").val(newFilter).focus().select(),$confirm.notify("error","Filter not saved")})):27===event.keyCode?($el.find(".my-filter-name").val(""),$el.find(".my-filter-name").addClass("hidden"),$el.find(".save-filters").show()):void 0})},{link:link}},module.directive("tgIssuesFilters",["$log","$tgLocation","$tgResources","$tgConfirm","$tgLoading","$tgTemplate",IssuesFiltersDirective]),IssueStatusInlineEditionDirective=function($repo,$template){var link,selectionTemplate,updateIssueStatus;return selectionTemplate=$template.get("issue/issue-status-inline-edition-selection.html",!0),updateIssueStatus=function($el,issue,issueStatusById){var issueStatusDom,issueStatusDomParent,status;return issueStatusDomParent=$el.find(".issue-status"),issueStatusDom=$el.find(".issue-status .issue-status-bind"),status=issueStatusById[issue.status],status?(issueStatusDom.text(status.name),issueStatusDom.prop("title",status.name),issueStatusDomParent.css("color",status.color)):void 0},link=function($scope,$el,$attrs){var $ctrl,issue;return $ctrl=$el.controller(),issue=$scope.$eval($attrs.tgIssueStatusInlineEdition),$el.on("click",".issue-status",function(event){return event.preventDefault(),event.stopPropagation(),$el.find(".pop-status").popover().open()}),$el.on("click",".status",function(event){var target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),issue.status=target.data("status-id"),$el.find(".pop-status").popover().close(),updateIssueStatus($el,issue,$scope.issueStatusById),$scope.$apply(function(){return $repo.save(issue).then})}),taiga.bindOnce($scope,"project",function(project){return $el.append(selectionTemplate({statuses:project.issue_statuses})),updateIssueStatus($el,issue,$scope.issueStatusById),-1===project.my_permissions.indexOf("modify_issue")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$watch($attrs.tgIssueStatusInlineEdition,function(){return function(val){return updateIssueStatus($el,val,$scope.issueStatusById)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssueStatusInlineEdition",["$tgRepo","$tgTemplate",IssueStatusInlineEditionDirective]),IssueAssignedToInlineEditionDirective=function($repo,$rootscope){var link,template;return template=_.template('<%- name %>\n
    <%- name %>
    '),link=function($scope,$el,$attrs){var $ctrl,issue,updateIssue;return updateIssue=function(issue){var ctx,member;return ctx={name:"Unassigned",imgurl:"/images/unnamed.png"},member=$scope.usersById[issue.assigned_to],member&&(ctx.imgurl=member.photo,ctx.name=member.full_name_display),$el.find(".avatar").html(template(ctx)),$el.find(".issue-assignedto").attr("title",ctx.name)},$ctrl=$el.controller(),issue=$scope.$eval($attrs.tgIssueAssignedToInlineEdition),updateIssue(issue),$el.on("click",".issue-assignedto",function(){return $rootscope.$broadcast("assigned-to:add",issue)}),taiga.bindOnce($scope,"project",function(project){return-1===project.my_permissions.indexOf("modify_issue")?($el.unbind("click"),$el.find("a").addClass("not-clickable")):void 0}),$scope.$on("assigned-to:added",function(){return function(ctx,userId,updatedIssue){return updatedIssue.id===issue.id?(updatedIssue.assigned_to=userId,$repo.save(updatedIssue),updateIssue(updatedIssue)):void 0}}(this)),$scope.$watch($attrs.tgIssueAssignedToInlineEdition,function(){return function(val){return updateIssue(val)}}(this)),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgIssueAssignedToInlineEdition",["$tgRepo","$rootScope",IssueAssignedToInlineEditionDirective])}.call(this),function(){var UsClientRequirementButtonDirective,UsStatusButtonDirective,UsStatusDisplayDirective,UsTasksProgressDisplayDirective,UsTeamRequirementButtonDirective,UserStoryDetailController,bindOnce,groupBy,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,module=angular.module("taigaUserStories"),UserStoryDetailController=function(_super){function UserStoryDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.usRef=this.params.usref,this.scope.sectionName="User Story Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.us.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(UserStoryDetailController,_super),UserStoryDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],UserStoryDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("related-tasks:update",function(_this){return function(){return _this.loadUs(),_this.scope.tasks=_.clone(_this.scope.tasks,!1)}}(this)),this.scope.$on("attachment:create",function(_this){return function(){return _this.analytics.trackEvent("attachment","create","create attachment on userstory",1),_this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this))},UserStoryDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;return ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.navUrls.resolve("project",ctx),this.scope.project.is_backlog_activated?this.scope.us.milestone?(ctx.sprint=this.scope.sprint.slug,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-taskboard",ctx)):this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-backlog",ctx):this.scope.project.is_kanban_activated?this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-kanban",ctx):void 0},UserStoryDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.us_statuses,_this.scope.statusById=groupBy(project.us_statuses,function(x){return x.id}),_this.scope.taskStatusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.pointsById=groupBy(_this.scope.pointsList,function(e){return e.id}),project}}(this))},UserStoryDetailController.prototype.loadUs=function(){return this.rs.userstories.getByRef(this.scope.projectId,this.params.usref).then(function(_this){return function(us){var ctx;return _this.scope.us=us,_this.scope.usId=us.id,_this.scope.commentModel=us,null!=_this.scope.us.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.us.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-userstories-detail",ctx)),null!=_this.scope.us.neighbors.next.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.us.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-userstories-detail",ctx)),us}}(this))},UserStoryDetailController.prototype.loadSprint=function(){return this.scope.us.milestone?this.rs.sprints.get(this.scope.us.project,this.scope.us.milestone).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,sprint}}(this)):void 0},UserStoryDetailController.prototype.loadTasks=function(){return this.rs.tasks.list(this.scope.projectId,null,this.scope.usId).then(function(_this){return function(tasks){return _this.scope.tasks=tasks,tasks}}(this))},UserStoryDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadUs().then(function(){return _this.q.all([_this.loadSprint(),_this.loadTasks()])})}}(this))},UserStoryDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserStoryDetailController",UserStoryDetailController),UsStatusDisplayDirective=function($template){var link,template;return template=$template.get("common/components/status-display.html",!0),link=function($scope,$el,$attrs){var render;return render=function(us){var html;return html=template({is_closed:us.is_closed,status:$scope.statusById[us.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(us){return null!=us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsStatusDisplay",["$tgTemplate",UsStatusDisplayDirective]),UsTasksProgressDisplayDirective=function($template){var link,template;return template=$template.get("us/us-task-progress.html",!0),link=function($scope,$el,$attrs){var render;return render=function(tasks){var html,progress,totalClosedTasks,totalTasks;return totalTasks=tasks.length,totalClosedTasks=_.filter(tasks,function(){return function(task){return $scope.taskStatusById[task.status].is_closed}}(this)).length,progress=totalTasks>0?100*totalClosedTasks/totalTasks:0,html=template({totalTasks:totalTasks,totalClosedTasks:totalClosedTasks,progress:progress}),$el.html(html)},$scope.$watch($attrs.ngModel,function(tasks){return null!=tasks?render(tasks):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsTasksProgressDisplay",["$tgTemplate",UsTasksProgressDisplayDirective]),UsStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("us/us-status-button.html",!0),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(){return function(us){var html,status;return status=$scope.statusById[us.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(status){var onError,onSuccess,us;return us=$model.$modelValue.clone(),us.status=status,$.fn.popover().closeAll(),$model.$setViewValue(us),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),us.revert(),$model.$setViewValue(us),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var status,target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),status=target.data("status-id"),save(status)):void 0}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",UsStatusButtonDirective]),UsTeamRequirementButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("us/us-team-requirement-button.html",!0),link=function($scope,$el,$attrs,$model){var canEdit,render,save;return canEdit=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var ctx,html;return canEdit()||us.team_requirement?(ctx={canEdit:canEdit(),isRequired:us.team_requirement},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(team_requirement){var promise,us;return us=$model.$modelValue.clone(),us.team_requirement=team_requirement,$model.$setViewValue(us),$loading.start($el.find("label")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $loading.finish($el.find("label")),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $loading.finish($el.find("label")),$confirm.notify("error"),us.revert(),$model.$setViewValue(us)})}}(this)),$el.on("click",".team-requirement",function(){var team_requirement;if(canEdit())return team_requirement=!$model.$modelValue.team_requirement,save(team_requirement)}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsTeamRequirementButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",UsTeamRequirementButtonDirective]),UsClientRequirementButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue,$template){var link,template;return template=$template.get("us/us-client-requirement-button.html",!0),link=function($scope,$el,$attrs,$model){var canEdit,render,save;return canEdit=function(){return-1!==$scope.project.my_permissions.indexOf("modify_us")},render=function(us){var ctx,html;return canEdit()||us.client_requirement?(ctx={canEdit:canEdit(),isRequired:us.client_requirement},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(client_requirement){var promise,us;return us=$model.$modelValue.clone(),us.client_requirement=client_requirement,$model.$setViewValue(us),$loading.start($el.find("label")),promise=$tgrepo.save($model.$modelValue),promise.then(function(){return $loading.finish($el.find("label")),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return $loading.finish($el.find("label")),$confirm.notify("error"),us.revert(),$model.$setViewValue(us)})}}(this)),$el.on("click",".client-requirement",function(){var client_requirement;if(canEdit())return client_requirement=!$model.$modelValue.client_requirement,save(client_requirement)}),$scope.$watch($attrs.ngModel,function(us){return us?render(us):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgUsClientRequirementButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue","$tgTemplate",UsClientRequirementButtonDirective])}.call(this),function(){var TaskDetailController,TaskIsIocaineButtonDirective,TaskStatusButtonDirective,TaskStatusDisplayDirective,groupBy,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,module=angular.module("taigaTasks"),TaskDetailController=function(_super){function TaskDetailController(scope,rootscope,repo,confirm,rs,params,q,location,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.taskRef=this.params.taskref,this.scope.sectionName="Task Details",this.initializeEventHandlers(),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.task.subject+" - "+_this.scope.project.name),_this.initializeOnDeleteGoToUrl()}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TaskDetailController,_super),TaskDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],TaskDetailController.prototype.initializeEventHandlers=function(){return this.scope.$on("attachment:create",function(_this){return function(){return _this.analytics.trackEvent("attachment","create","create attachment on task",1),_this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:edit",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this)),this.scope.$on("attachment:delete",function(_this){return function(){return _this.rootscope.$broadcast("history:reload")}}(this))},TaskDetailController.prototype.initializeOnDeleteGoToUrl=function(){var ctx;if(ctx={project:this.scope.project.slug},this.scope.onDeleteGoToUrl=this.navUrls.resolve("project",ctx),this.scope.project.is_backlog_activated){if(this.scope.task.milestone)return ctx.sprint=this.scope.sprint.slug,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-taskboard",ctx);if(this.scope.task.us)return ctx.ref=this.scope.us.ref,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-userstories-detail",ctx)}else if(this.scope.project.is_kanban_activated&&this.scope.us)return ctx.ref=this.scope.us.ref,this.scope.onDeleteGoToUrl=this.navUrls.resolve("project-userstories-detail",ctx)},TaskDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.statusList=project.task_statuses,_this.scope.statusById=groupBy(project.task_statuses,function(x){return x.id}),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},TaskDetailController.prototype.loadTask=function(){return this.rs.tasks.getByRef(this.scope.projectId,this.params.taskref).then(function(_this){return function(task){var ctx;return _this.scope.task=task,_this.scope.taskId=task.id,_this.scope.commentModel=task,null!=_this.scope.task.neighbors.previous.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.task.neighbors.previous.ref},_this.scope.previousUrl=_this.navUrls.resolve("project-tasks-detail",ctx)),null!=_this.scope.task.neighbors.next.ref&&(ctx={project:_this.scope.project.slug,ref:_this.scope.task.neighbors.next.ref},_this.scope.nextUrl=_this.navUrls.resolve("project-tasks-detail",ctx)),task}}(this))},TaskDetailController.prototype.loadSprint=function(){return this.scope.task.milestone?this.rs.sprints.get(this.scope.task.project,this.scope.task.milestone).then(function(_this){return function(sprint){return _this.scope.sprint=sprint,sprint}}(this)):void 0},TaskDetailController.prototype.loadUserStory=function(){return this.scope.task.user_story?this.rs.userstories.get(this.scope.task.project,this.scope.task.user_story).then(function(_this){return function(us){return _this.scope.us=us,us}}(this)):void 0},TaskDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadTask().then(function(){return _this.q.all([_this.loadSprint(),_this.loadUserStory()])})}}(this))},TaskDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TaskDetailController",TaskDetailController),TaskStatusDisplayDirective=function($template){var link,template;return template=$template.get("common/components/status-display.html",!0),link=function($scope,$el,$attrs){var render;return render=function(task){var html;return html=template({status:$scope.statusById[task.status]}),$el.html(html)},$scope.$watch($attrs.ngModel,function(task){return null!=task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskStatusDisplay",["$tgTemplate",TaskStatusDisplayDirective]),TaskStatusButtonDirective=function($rootScope,$repo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n <%- status.name %>\n <% if(editable){ %><% }%>\n status\n\n
      \n <% _.each(statuses, function(st) { %>\n
    • <%- st.name %>
    • \n <% }); %>\n
    \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_task")},render=function(){return function(task){var html,status;return status=$scope.statusById[task.status],html=template({status:status,statuses:$scope.statusList,editable:isEditable()}),$el.html(html)}}(this),save=$qqueue.bindAdd(function(){return function(status){var onError,onSuccess,task;return task=$model.$modelValue.clone(),task.status=status,$model.$setViewValue(task),onSuccess=function(){return $confirm.notify("success"),$rootScope.$broadcast("history:reload"),$loading.finish($el.find(".level-name"))},onError=function(){return $confirm.notify("error"),task.revert(),$model.$setViewValue(task),$loading.finish($el.find(".level-name"))},$loading.start($el.find(".level-name")),$repo.save($model.$modelValue).then(onSuccess,onError)}}(this)),$el.on("click",".status-data",function(event){return event.preventDefault(),event.stopPropagation(),isEditable()?$el.find(".pop-status").popover().open():void 0}),$el.on("click",".status",function(event){var target;return event.preventDefault(),event.stopPropagation(),isEditable()?(target=angular.element(event.currentTarget),$.fn.popover().closeAll(),save(target.data("status-id"))):void 0}),$scope.$watch($attrs.ngModel,function(task){return task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskStatusButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",TaskStatusButtonDirective]),TaskIsIocaineButtonDirective=function($rootscope,$tgrepo,$confirm,$loading,$qqueue){var link,template;return template=_.template('
    \n \n \n
    '),link=function($scope,$el,$attrs,$model){var isEditable,render,save;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_task")},render=function(task){var ctx,html;return isEditable()||task.is_iocaine?(ctx={isIocaine:task.is_iocaine,isEditable:isEditable()},html=template(ctx),$el.html(html)):void $el.html("")},save=$qqueue.bindAdd(function(){return function(is_iocaine){var promise,task;return task=$model.$modelValue.clone(),task.is_iocaine=is_iocaine,$model.$setViewValue(task),$loading.start($el.find("label")),promise=$tgrepo.save(task),promise.then(function(){return $confirm.notify("success"),$rootscope.$broadcast("history:reload")}),promise.then(null,function(){return task.revert(),$model.$setViewValue(task),$confirm.notify("error")}),promise["finally"](function(){return $loading.finish($el.find("label"))})}}(this)),$el.on("click",".is-iocaine",function(){var is_iocaine;if(isEditable())return is_iocaine=!$model.$modelValue.is_iocaine,save(is_iocaine)}),$scope.$watch($attrs.ngModel,function(task){return task?render(task):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgTaskIsIocaineButton",["$rootScope","$tgRepo","$tgConfirm","$tgLoading","$tgQqueue",TaskIsIocaineButtonDirective])}.call(this),function(){var LeaveProjectDirective,TeamController,TeamFiltersDirective,TeamMemberCurrentUserDirective,TeamMemberStatsDirective,TeamMembersDirective,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child +};taiga=this.taiga,mixOf=this.taiga.mixOf,module=angular.module("taigaTeam"),TeamController=function(_super){function TeamController(scope,rootscope,repo,rs,params,q,location,navUrls,appTitle,auth,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.auth=auth,this.scope.sectionName="Team",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Team - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(TeamController,_super),TeamController.$inject=["$scope","$rootScope","$tgRepo","$tgResources","$routeParams","$q","$location","$tgNavUrls","$appTitle","$tgAuth","tgLoader"],TeamController.prototype.setRole=function(role){return this.scope.filtersRole=role?role:""},TeamController.prototype.loadMembers=function(){return this.rs.memberships.list(this.scope.projectId,{},!1).then(function(_this){return function(data){var currentUser,membership,_i,_len,_ref;for(currentUser=_this.auth.getUser(),null==currentUser.photo&&(currentUser.photo="/images/unnamed.png"),_this.scope.currentUser=_.find(data,function(membership){return membership.user===currentUser.id}),_this.scope.totals={},_.forEach(data,function(membership){return _this.scope.totals[membership.user]=0}),_this.scope.memberships=_.filter(data,function(membership){return membership.user&&membership.user!==currentUser.id&&membership.is_user_active?membership:void 0}),_ref=_this.scope.memberships,_i=0,_len=_ref.length;_len>_i;_i++)membership=_ref[_i],null==membership.photo&&(membership.photo="/images/unnamed.png");return data}}(this))},TeamController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.issuesEnabled=project.is_issues_activated,_this.scope.tasksEnabled=project.is_kanban_activated||project.is_backlog_activated,_this.scope.wikiEnabled=project.is_wiki_activated,project}}(this))},TeamController.prototype.loadMemberStats=function(){return this.rs.projects.memberStats(this.scope.projectId).then(function(_this){return function(stats){var totals;return totals={},_.forEach(_this.scope.totals,function(total,userId){var vals;return vals=_.map(stats,function(memberStats){return memberStats[userId]}),total=_.reduce(vals,function(sum,el){return sum+el}),_this.scope.totals[userId]=total}),_this.scope.stats=_this.processStats(stats),_this.scope.stats.totals=_this.scope.totals}}(this))},TeamController.prototype.processStat=function(stat){var max,min,singleStat;return max=_.max(stat),min=_.min(stat),singleStat=_.map(stat,function(value,key){return value===min?[key,.1]:value===max?[key,1]:[key,.5*value/max]}),singleStat=_.object(singleStat)},TeamController.prototype.processStats=function(stats){var key,value;for(key in stats)value=stats[key],stats[key]=this.processStat(value);return stats},TeamController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.loadMembers().then(function(){return _this.loadMemberStats()})}}(this))},TeamController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("TeamController",TeamController),TeamFiltersDirective=function(){return{templateUrl:"team/team-filter.html"}},module.directive("tgTeamFilters",[TeamFiltersDirective]),TeamMemberStatsDirective=function(){return{templateUrl:"team/team-member-stats.html",scope:{stats:"=",userId:"=user",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamMemberStats",TeamMemberStatsDirective),TeamMemberCurrentUserDirective=function(){return{templateUrl:"team/team-member-current-user.html",scope:{projectId:"=projectid",currentUser:"=currentuser",stats:"=",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamCurrentUser",TeamMemberCurrentUserDirective),TeamMembersDirective=function(){var template;return template="team/team-members.html",{templateUrl:template,scope:{memberships:"=",filtersQ:"=filtersq",filtersRole:"=filtersrole",stats:"=",issuesEnabled:"=issuesenabled",tasksEnabled:"=tasksenabled",wikiEnabled:"=wikienabled"}}},module.directive("tgTeamMembers",TeamMembersDirective),LeaveProjectDirective=function($repo,$confirm,$location,$rs,$navurls){var link;return link=function($scope,$el,$attrs){return $scope.leave=function(){return $confirm.ask("Leave this project","Are you sure you want to leave the project?").then(function(){return function(finish){var promise;return promise=$rs.projects.leave($attrs.projectid),promise.then(function(){return finish(),$confirm.notify("success"),$location.path($navurls.resolve("home"))}),promise.then(null,function(response){return finish(),$confirm.notify("error",response.data._error_message)})}}(this))}},{scope:{},templateUrl:"team/leave-project.html",link:link}},module.directive("tgLeaveProject",["$tgRepo","$tgConfirm","$tgLocation","$tgResources","$tgNavUrls",LeaveProjectDirective])}.call(this),function(){var EditableWikiContentDirective,WikiDetailController,WikiSummaryDirective,bindOnce,debounce,groupBy,mixOf,module,taiga,unslugify,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,unslugify=this.taiga.unslugify,debounce=this.taiga.debounce,module=angular.module("taigaWiki"),WikiDetailController=function(_super){function WikiDetailController(scope,rootscope,repo,model,confirm,rs,params,q,location,filter,log,appTitle,navUrls,analytics,tgLoader){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.model=model,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.filter=filter,this.log=log,this.appTitle=appTitle,this.navUrls=navUrls,this.analytics=analytics,this.scope.projectSlug=this.params.pslug,this.scope.wikiSlug=this.params.slug,this.scope.sectionName="Wiki",promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Wiki - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(WikiDetailController,_super),WikiDetailController.$inject=["$scope","$rootScope","$tgRepo","$tgModel","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$filter","$log","$appTitle","$tgNavUrls","$tgAnalytics","tgLoader"],WikiDetailController.prototype.loadProject=function(){return this.rs.projects.getBySlug(this.params.pslug).then(function(_this){return function(project){return _this.scope.projectId=project.id,_this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.membersById=groupBy(project.memberships,function(x){return x.user}),project}}(this))},WikiDetailController.prototype.loadWiki=function(){var promise;return promise=this.rs.wiki.getBySlug(this.scope.projectId,this.params.slug),promise.then(function(_this){return function(wiki){return _this.scope.wiki=wiki,_this.scope.wikiId=wiki.id,_this.scope.wiki}}(this)),promise.then(null,function(_this){return function(){var data;return _this.scope.wikiId=null,-1===_this.scope.project.my_permissions.indexOf("add_wiki_page")?null:(data={project:_this.scope.projectId,slug:_this.scope.wikiSlug,content:""},_this.scope.wiki=_this.model.make_model("wiki",data),_this.scope.wiki)}}(this))},WikiDetailController.prototype.loadWikiLinks=function(){return this.rs.wiki.listLinks(this.scope.projectId).then(function(_this){return function(wikiLinks){return _this.scope.wikiLinks=wikiLinks}}(this))},WikiDetailController.prototype.loadInitialData=function(){var promise;return promise=this.loadProject(),promise.then(function(_this){return function(project){return _this.fillUsersAndRoles(project.users,project.roles),_this.q.all([_this.loadWikiLinks(),_this.loadWiki()])}}(this))},WikiDetailController.prototype["delete"]=function(){var message,title;return title="Delete Wiki Page",message=unslugify(this.scope.wiki.slug),this.confirm.askOnDelete(title,message).then(function(_this){return function(finish){var onError,onSuccess;return onSuccess=function(){var ctx;return finish(),ctx={project:_this.scope.projectSlug},_this.location.path(_this.navUrls.resolve("project-wiki",ctx)),_this.confirm.notify("success")},onError=function(){return finish(!1),_this.confirm.notify("error")},_this.repo.remove(_this.scope.wiki).then(onSuccess,onError)}}(this))},WikiDetailController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("WikiDetailController",WikiDetailController),WikiSummaryDirective=function($log,$template){var link,template;return template=$template.get("wiki/wiki-summary.html",!0),link=function($scope,$el,$attrs){var render;return render=function(wiki){var ctx,html,user;return null==$scope.usersById?$log.error("WikiSummaryDirective requires userById set in scope."):user=$scope.usersById[wiki.last_modifier],user=void 0===user?{name:"unknown",imgUrl:"/images/unnamed.png"}:{name:user.full_name_display,imgUrl:user.photo},ctx={totalEditions:wiki.editions,lastModifiedDate:moment(wiki.modified_date).format("DD MMM YYYY HH:mm"),user:user},html=template(ctx),$el.html(html)},$scope.$watch($attrs.ngModel,function(wikiPage){return wikiPage?render(wikiPage):void 0}),$scope.$on("wiki:edit",function(event,wikiPage){return render(wikiPage)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgWikiSummary",["$log","$tgTemplate",WikiSummaryDirective]),EditableWikiContentDirective=function($window,$document,$repo,$confirm,$loading,$location,$navUrls,$analytics,$qqueue){var link;return link=function($scope,$el,$attrs,$model){var cancelEdition,disableEdition,getSelectedText,isEditable,save,switchToEditMode,switchToReadMode;return isEditable=function(){return-1!==$scope.project.my_permissions.indexOf("modify_wiki_page")},switchToEditMode=function(){return $el.find(".edit-wiki-content").show(),$el.find(".view-wiki-content").hide(),$el.find("textarea").focus()},switchToReadMode=function(){return $el.find(".edit-wiki-content").hide(),$el.find(".view-wiki-content").show()},disableEdition=function(){return $el.find(".view-wiki-content .edit").remove(),$el.find(".edit-wiki-content").remove()},cancelEdition=function(){var ctx;if($scope.wiki.html)return $scope.wiki.id?($scope.$apply(function(){return function(){return $scope.wiki.revert()}}(this)),switchToReadMode()):(ctx={project:$scope.projectSlug},$location.path($navUrls.resolve("project-wiki",ctx)))},getSelectedText=function(){return $window.getSelection?$window.getSelection().toString():$document.selection?$document.selection.createRange().text:null},save=$qqueue.bindAdd(function(wiki){var onError,onSuccess,promise;return onSuccess=function(wikiPage){return null==wiki.id&&$analytics.trackEvent("wikipage","create","create wiki page",1),$scope.wiki=wikiPage,$model.setModelValue=wiki,$confirm.notify("success"),switchToReadMode(),$scope.$broadcast("wiki:edit",wikiPage)},onError=function(){return $confirm.notify("error")},$loading.start($el.find(".save-container")),promise=null!=wiki.id?$repo.save(wiki).then(onSuccess,onError):$repo.create("wiki",wiki).then(onSuccess,onError),promise["finally"](function(){return $loading.finish($el.find(".save-container"))})}),$el.on("mousedown",".view-wiki-content",function(event){var target;return target=angular.element(event.target),target.is("pre")?target.data("scroll-pos",target[0].scrollLeft):void 0}),$el.on("mouseup",".view-wiki-content",function(event){var prevPos,target;return target=angular.element(event.target),!isEditable()||target.is("a")||getSelectedText()||target.is("pre")&&(prevPos=target.data("scroll-pos"),target.data("scroll-pos",null),prevPos!==target[0].scrollLeft)?void 0:switchToEditMode()}),$el.on("click",".save",debounce(2e3,function(){return save($scope.wiki)})),$el.on("click",".cancel",function(){return cancelEdition()}),$el.on("keydown","textarea",function(event){return 27===event.keyCode?cancelEdition():void 0}),$scope.$watch($attrs.ngModel,function(wikiPage){return wikiPage?($scope.wiki=wikiPage,isEditable()?($el.addClass("editable"),null==wikiPage.id?switchToEditMode():void 0):disableEdition()):void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,restrict:"EA",require:"ngModel",templateUrl:"wiki/editable-wiki-content.html"}},module.directive("tgEditableWikiContent",["$window","$document","$tgRepo","$tgConfirm","$tgLoading","$tgLocation","$tgNavUrls","$tgAnalytics","$tgQqueue",EditableWikiContentDirective])}.call(this),function(){var WikiNavDirective,bindOnce,groupBy,mixOf,module,slugify,taiga,unslugify;taiga=this.taiga,mixOf=this.taiga.mixOf,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,slugify=this.taiga.slugify,unslugify=this.taiga.slugify,module=angular.module("taigaWiki"),WikiNavDirective=function($tgrepo,$log,$location,$confirm,$navUrls,$analytics,$loading,$template){var link,template;return template=$template.get("wiki/wiki-nav.html",!0),link=function($scope,$el,$attrs){var $ctrl,render;return $ctrl=$el.controller(),null==$attrs.ngModel?$log.error("WikiNavDirective: no ng-model attr is defined"):(render=function(wikiLinks){var addWikiLinkPermission,deleteWikiLinkPermission,html;return addWikiLinkPermission=$scope.project.my_permissions.indexOf("add_wiki_link")>-1,deleteWikiLinkPermission=$scope.project.my_permissions.indexOf("delete_wiki_link")>-1,html=template({wikiLinks:wikiLinks,projectSlug:$scope.projectSlug,addWikiLinkPermission:addWikiLinkPermission,deleteWikiLinkPermission:deleteWikiLinkPermission}),$el.off(),$el.html(html),$el.on("click",".wiki-link .link-title",function(event){var linkId,linkSlug,target;return event.preventDefault(),target=angular.element(event.currentTarget),linkId=target.parents(".wiki-link").data("id"),linkSlug=$scope.wikiLinks[linkId].href,$scope.$apply(function(){var ctx;return ctx={project:$scope.projectSlug,slug:linkSlug},$location.path($navUrls.resolve("project-wiki-page",ctx))})}),$el.on("click",".add-button",function(event){return event.preventDefault(),$el.find(".new").removeClass("hidden"),$el.find(".new input").focus(),$el.find(".add-button").hide()}),$el.on("click",".wiki-link .icon-delete",function(event){var linkId,message,target,title;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),linkId=target.parents(".wiki-link").data("id"),title="Delete Wiki Link",message=$scope.wikiLinks[linkId].title,$confirm.askOnDelete(title,message).then(function(){return function(finish){var promise;return promise=$tgrepo.remove($scope.wikiLinks[linkId]),promise.then(function(){return promise=$ctrl.loadWikiLinks(),promise.then(function(){return finish(),render($scope.wikiLinks)}),promise.then(null,function(){return finish()})}),promise.then(null,function(){return finish(!1),$confirm.notify("error")})}}(this))}),$el.on("keyup",".new input",function(event){var newLink,promise,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newLink=target.val(),$loading.start($el.find(".new")),promise=$tgrepo.create("wiki-links",{project:$scope.projectId,title:newLink,href:slugify(newLink)}),promise.then(function(){var loadPromise;return $analytics.trackEvent("wikilink","create","create wiki link",1),loadPromise=$ctrl.loadWikiLinks(),loadPromise.then(function(){return $loading.finish($el.find(".new")),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show(),render($scope.wikiLinks)}),loadPromise.then(null,function(){return $loading.finish($el.find(".new")),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show(),$confirm.notify("error","Error loading wiki links")})}),promise.then(null,function(error){var _ref;return $loading.finish($el.find(".new")),$el.find(".new input").val(newLink),$el.find(".new input").focus().select(),null!=(null!=error&&null!=(_ref=error.__all__)?_ref[0]:void 0)?$confirm.notify("error","The link already exists"):$confirm.notify("error")})):27===event.keyCode?(target=angular.element(event.currentTarget),$el.find(".new").addClass("hidden"),$el.find(".new input").val(""),$el.find(".add-button").show()):void 0})},bindOnce($scope,$attrs.ngModel,render))},{link:link}},module.directive("tgWikiNav",["$tgRepo","$log","$tgLocation","$tgConfirm","$tgNavUrls","$tgAnalytics","$tgLoading","$tgTemplate",WikiNavDirective])}.call(this),function(){var CreateMembersDirective,MAX_MEMBERSHIP_FIELDSETS,debounce,module,taiga;taiga=this.taiga,debounce=this.taiga.debounce,module=angular.module("taigaKanban"),MAX_MEMBERSHIP_FIELDSETS=4,CreateMembersDirective=function($rs,$rootScope,$confirm,$loading,lightboxService){var extraTextTemplate,link,template;return extraTextTemplate='
    \n \n
    ',template=_.template('
    \n
    \n data-required="true" <% } %> data-type="email" />\n
    \n
    \n \n \n
    \n
    '),link=function($scope,$el){var createFieldSet,resetForm,submit,submitButton;return createFieldSet=function(required){var ctx;return null==required&&(required=!0),ctx={roleList:$scope.roles,required:required},template(ctx)},resetForm=function(){var fieldSet,invitations;return $el.find("form textarea").remove(""),$el.find("form .add-member-wrapper").remove(),invitations=$el.find(".add-member-forms"),invitations.html(extraTextTemplate),fieldSet=createFieldSet(),invitations.prepend(fieldSet)},$scope.$on("membersform:new",function(){return resetForm(),lightboxService.open($el)}),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click",".delete-fieldset",function(event){var fieldSet,lastActionButton,target;return event.preventDefault(),target=angular.element(event.currentTarget),fieldSet=target.closest(".add-member-wrapper"),fieldSet.remove(),lastActionButton=$el.find("fieldset:last > a"),lastActionButton.hasClass("icon-delete delete-fieldset")?lastActionButton.removeClass("icon-delete delete-fieldset").addClass("icon-plus add-fieldset"):void 0}),$el.on("click",".add-fieldset",function(event){var fieldSet,newFieldSet,target;return event.preventDefault(),target=angular.element(event.currentTarget),fieldSet=target.closest(".add-member-wrapper"),target.removeClass("icon-plus add-fieldset").addClass("icon-delete delete-fieldset"),newFieldSet=createFieldSet(!1),fieldSet.after(newFieldSet),$el.find(".add-member-wrapper").length===MAX_MEMBERSHIP_FIELDSETS?$el.find(".add-member-wrapper fieldset:last > a").removeClass("icon-plus add-fieldset").addClass("icon-delete delete-fieldset"):void 0}),submit=debounce(2e3,function(){return function(event){var form,invitation_extra_text,invitations,memberWrappers,onError,onSuccess;return event.preventDefault(),$loading.start(submitButton),onSuccess=function(){return $loading.finish(submitButton),lightboxService.close($el),$confirm.notify("success"),$rootScope.$broadcast("membersform:new:success")},onError=function(){return $loading.finish(submitButton),lightboxService.close($el),$confirm.notify("error"),$rootScope.$broadcast("membersform:new:error")},form=$el.find("form").checksley(),form.destroy(),form.initialize(),form.validate()?(memberWrappers=$el.find("form .add-member-wrapper"),memberWrappers=_.filter(memberWrappers,function(mw){return angular.element(mw).find("input").hasClass("checksley-ok")}),invitations=_.map(memberWrappers,function(mw){var email,memberWrapper,role;return memberWrapper=angular.element(mw),email=memberWrapper.find("input"),role=memberWrapper.find("select"),{email:email.val(),role_id:role.val()}}),invitations.length?(invitation_extra_text=$el.find("form textarea").val(),$rs.memberships.bulkCreateMemberships($scope.project.id,invitations,invitation_extra_text).then(onSuccess,onError)):void 0):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgLbCreateMembers",["$tgResources","$rootScope","$tgConfirm","$tgLoading","lightboxService",CreateMembersDirective])}.call(this),function(){var MembershipsController,MembershipsDirective,MembershipsRowActionsDirective,MembershipsRowAdminCheckboxDirective,MembershipsRowAvatarDirective,MembershipsRowRoleSelectorDirective,bindMethods,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindMethods=this.taiga.bindMethods,module=angular.module("taigaAdmin"),MembershipsController=function(_super){function MembershipsController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,analytics,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.analytics=analytics,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Manage Members",this.scope.project={},this.scope.filters={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Membership - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("membersform:new:success",function(_this){return function(){return _this.loadMembers(),_this.analytics.trackEvent("membership","create","create memberships on admin",1)}}(this))}return __extends(MembershipsController,_super),MembershipsController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAnalytics","$appTitle"],MembershipsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},MembershipsController.prototype.loadMembers=function(){var httpFilters;return httpFilters=this.getUrlFilters(),this.rs.memberships.list(this.scope.projectId,httpFilters).then(function(_this){return function(data){return _this.scope.memberships=_.filter(data.models,function(membership){return null===membership.user||membership.is_user_active}),_this.scope.page=data.current,_this.scope.count=data.count,_this.scope.paginatedBy=data.paginatedBy,data}}(this))},MembershipsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadMembers()}}(this))},MembershipsController.prototype.getUrlFilters=function(){var filters;return filters=_.pick(this.location.search(),"page"),filters.page||(filters.page=1),filters},MembershipsController.prototype.addNewMembers=function(){return this.rootscope.$broadcast("membersform:new")},MembershipsController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("MembershipsController",MembershipsController),MembershipsDirective=function($template){var link,linkPagination,template;return template=$template.get("admin/admin-membership-paginator.html",!0),linkPagination=function($scope,$el,$attrs,$ctrl){var $pagEl,afterCurrent,atBegin,atEnd,beforeCurrent,getNumPages,renderPagination;return afterCurrent=2,beforeCurrent=4,atBegin=2,atEnd=2,$pagEl=$el.find(".memberships-paginator"),getNumPages=function(){var numPages;return numPages=$scope.count/$scope.paginatedBy,numPages=parseInt(numPages,10)=numPages)return void $pagEl.hide();for(pages=[],options={},options.pages=pages,options.showPrevious=$scope.page>1,options.showNext=!($scope.page===numPages),cpage=$scope.page,i=_i=1;numPages>=1?numPages>=_i:_i>=numPages;i=numPages>=1?++_i:--_i)i===cpage+afterCurrent&&numPages>cpage+afterCurrent+atEnd?pages.push({classes:"dots",type:"dots"}):i===cpage-beforeCurrent&&cpage>atBegin+beforeCurrent?pages.push({classes:"dots",type:"dots"}):i>cpage+afterCurrent&&numPages-atEnd>=i||cpage-beforeCurrent>i&&i>atBegin||pages.push(i===cpage?{classes:"active",num:i,type:"page-active"}:{classes:"page",num:i,type:"page"});return $pagEl.html(template(options))},$scope.$watch("memberships",function(value){return value?renderPagination():void 0}),$el.on("click",".memberships-paginator a.next",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page+1),$ctrl.loadMembers()})}),$el.on("click",".memberships-paginator a.previous",function(event){return event.preventDefault(),$scope.$apply(function(){return $ctrl.selectFilter("page",$scope.page-1),$ctrl.loadMembers()})}),$el.on("click",".memberships-paginator li.page > a",function(event){var pagenum,target;return event.preventDefault(),target=angular.element(event.currentTarget),pagenum=target.data("pagenum"),$scope.$apply(function(){return $ctrl.selectFilter("page",pagenum),$ctrl.loadMembers()})})},link=function($scope,$el,$attrs){var $ctrl;return $ctrl=$el.controller(),linkPagination($scope,$el,$attrs,$ctrl),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgMemberships",["$tgTemplate",MembershipsDirective]),MembershipsRowAvatarDirective=function($log,$template){var link,template;return template=$template.get("admin/memberships-row-avatar.html",!0),link=function($scope,$el,$attrs){var member,render;return render=function(member){var ctx,html;return ctx={full_name:member.full_name?member.full_name:"",email:member.user_email?member.user_email:member.email,imgurl:member.photo?member.photo:"/images/unnamed.png"},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowAvatar?$log.error("MembershipsRowAvatarDirective: the directive need a member"):(member=$scope.$eval($attrs.tgMembershipsRowAvatar),render(member),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowAvatar",["$log","$tgTemplate",MembershipsRowAvatarDirective]),MembershipsRowAdminCheckboxDirective=function($log,$repo,$confirm,$template){var link,template;return template=$template.get("admin/admin-memberships-row-checkbox.html",!0),link=function($scope,$el,$attrs){var html,member,render;return render=function(member){var ctx,html;return ctx={inputId:"is-admin-"+member.id},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowAdminCheckbox?$log.error("MembershipsRowAdminCheckboxDirective: the directive need a member"):(member=$scope.$eval($attrs.tgMembershipsRowAdminCheckbox),html=render(member),member.is_owner&&$el.find(":checkbox").prop("checked",!0),$el.on("click",":checkbox",function(){return function(event){var onError,onSuccess,target;return onSuccess=function(){return $confirm.notify("success")},onError=function(data){return member.revert(),$el.find(":checkbox").prop("checked",member.is_owner),$confirm.notify("error",data.is_owner[0])},target=angular.element(event.currentTarget),member.is_owner=target.prop("checked"),$repo.save(member).then(onSuccess,onError)}}(this)),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowAdminCheckbox",["$log","$tgRepo","$tgConfirm","$tgTemplate",MembershipsRowAdminCheckboxDirective]),MembershipsRowRoleSelectorDirective=function($log,$repo,$confirm){var link,template;return template=_.template(''),link=function($scope,$el,$attrs){var $ctrl,html,member,render;return render=function(member){var ctx,html;return ctx={roleList:$scope.roles,selectedRole:member.role},html=template(ctx),$el.html(html)},null==$attrs.tgMembershipsRowRoleSelector?$log.error("MembershipsRowRoleSelectorDirective: the directive need a member"):($ctrl=$el.controller(),member=$scope.$eval($attrs.tgMembershipsRowRoleSelector),html=render(member),$el.on("click","select",function(){return function(event){var newRole,onError,onSuccess,target;return onSuccess=function(){return $confirm.notify("success")},onError=function(){return $confirm.notify("error")},target=angular.element(event.currentTarget),newRole=parseInt(target.val(),10),member.role!==newRole?(member.role=newRole,$repo.save(member).then(onSuccess,onError)):void 0}}(this)),$scope.$on("$destroy",function(){return $el.off()}))},{link:link}},module.directive("tgMembershipsRowRoleSelector",["$log","$tgRepo","$tgConfirm",MembershipsRowRoleSelectorDirective]),MembershipsRowActionsDirective=function($log,$repo,$rs,$confirm){var activedTemplate,link,pendingTemplate;return activedTemplate=_.template('
    \n Active\n
    \n\n \n'),pendingTemplate=_.template('\n Pending\n \n\n\n \n'),link=function($scope,$el,$attrs){var $ctrl,member,render;return render=function(member){var html;return html=member.user?activedTemplate():pendingTemplate(),$el.html(html)},null==$attrs.tgMembershipsRowActions?$log.error("MembershipsRowActionsDirective: the directive need a member"):($ctrl=$el.controller(),member=$scope.$eval($attrs.tgMembershipsRowActions),render(member),$el.on("click",".pending",function(event){var onError,onSuccess;return event.preventDefault(),onSuccess=function(){return $confirm.notify("success","We've sent the invitationi again to '"+$scope.member.email+"'.")},onError=function(){return $confirm.notify("error","We haven't sent the invitation.")},$rs.memberships.resendInvitation($scope.member.id).then(onSuccess,onError)}),$el.on("click",".delete",function(event){var message,title;return event.preventDefault(),title="Delete member",message=member.user?member.full_name:"the invitation to "+member.email,$confirm.askOnDelete(title,message).then(function(finish){var onError,onSuccess;return onSuccess=function(){return finish(),$ctrl.loadMembers(),$confirm.notify("success",null,"We've deleted "+message+".")},onError=function(){return finish(!1),$confirm.notify("error",null,"We have not been able to delete "+message+".")},$repo.remove(member).then(onSuccess,onError)})}),$scope.$on("$destroy",function(){return $el.off() +}))},{link:link}},module.directive("tgMembershipsRowActions",["$log","$tgRepo","$tgResources","$tgConfirm",MembershipsRowActionsDirective])}.call(this),function(){var AdminNavigationDirective,module;AdminNavigationDirective=function(){var link;return link=function($scope,$el,$attrs){var section;return section=$attrs.tgAdminNavigation,$el.find(".active").removeClass("active"),$el.find("#adminmenu-"+section+" a").addClass("active"),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaAdmin"),module.directive("tgAdminNavigation",AdminNavigationDirective)}.call(this),function(){var ProjectDefaultValuesDirective,ProjectExportDirective,ProjectModulesDirective,ProjectProfileController,ProjectProfileDirective,bindOnce,debounce,groupBy,joinStr,mixOf,module,taiga,toString,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaAdmin"),ProjectProfileController=function(_super){function ProjectProfileController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Project profile - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:loaded",function(_this){return function(){return _this.appTitle.set("Project profile - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this))}return __extends(ProjectProfileController,_super),ProjectProfileController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],ProjectProfileController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.pointsList=_.sortBy(project.points,"order"),_this.scope.usStatusList=_.sortBy(project.us_statuses,"order"),_this.scope.taskStatusList=_.sortBy(project.task_statuses,"order"),_this.scope.prioritiesList=_.sortBy(project.priorities,"order"),_this.scope.severitiesList=_.sortBy(project.severities,"order"),_this.scope.issueTypesList=_.sortBy(project.issue_types,"order"),_this.scope.issueStatusList=_.sortBy(project.issue_statuses,"order"),_this.scope.$emit("project:loaded",project),project}}(this))},ProjectProfileController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},ProjectProfileController.prototype.openDeleteLightbox=function(){return this.rootscope.$broadcast("deletelightbox:new",this.scope.project)},ProjectProfileController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("ProjectProfileController",ProjectProfileController),ProjectProfileDirective=function($repo,$confirm,$loading,$navurls,$location){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.save($scope.project),promise.then(function(){var newUrl;return $loading.finish(submitButton),$confirm.notify("success"),newUrl=$navurls.resolve("project-admin-project-profile-details",{project:$scope.project.slug}),$location.path(newUrl),$scope.$emit("project:loaded",$scope.project)}),promise.then(null,function(data){return $loading.finish(target),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgProjectProfile",["$tgRepo","$tgConfirm","$tgLoading","$tgNavUrls","$tgLocation",ProjectProfileDirective]),ProjectDefaultValuesDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.save($scope.project),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(data){return $loading.finish(target),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgProjectDefaultValues",["$tgRepo","$tgConfirm","$tgLoading",ProjectDefaultValuesDirective]),ProjectModulesDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit;return form=$el.find("form").checksley(),submit=function(){return function(){var promise,target;if(form.validate())return target=angular.element(".admin-functionalities a.button-green"),$loading.start(target),promise=$repo.save($scope.project),promise.then(function(){return $loading.finish(target),$confirm.notify("success"),$scope.$emit("project:loaded",$scope.project)}),promise.then(null,function(data){return $loading.finish(target),$confirm.notify("error",data._error_message)})}}(this),$el.on("submit","form",function(event){return event.preventDefault(),submit()}),$el.on("click",".admin-functionalities a.button-green",function(event){return event.preventDefault(),submit()}),$scope.$watch("isVideoconferenceActivated",function(isVideoconferenceActivated){return isVideoconferenceActivated?$el.find(".videoconference-attributes").removeClass("hidden"):($el.find(".videoconference-attributes").addClass("hidden"),$scope.project.videoconferences=null,$scope.project.videoconferences_salt="")}),$scope.$watch("project",function(project){return $scope.isVideoconferenceActivated=null!=project.videoconferences?!0:!1})},{link:link}},module.directive("tgProjectModules",["$tgRepo","$tgConfirm","$tgLoading",ProjectModulesDirective]),ProjectExportDirective=function($window,$rs,$confirm){var link;return link=function($scope,$el){var buttonsEl,hideButtons,hideResult,hideSpinner,resultEl,resultMessageEl,resultTitleEl,setAsyncMessage,setAsyncTitle,setLoadingMessage,setLoadingTitle,setSyncMessage,setSyncTitle,showButtons,showErrorMode,showExportResultAsyncMode,showExportResultSyncMode,showLoadingMode,showResult,showSpinner,spinnerEl;return buttonsEl=$el.find(".admin-project-export-buttons"),showButtons=function(){return buttonsEl.removeClass("hidden")},hideButtons=function(){return buttonsEl.addClass("hidden")},resultEl=$el.find(".admin-project-export-result"),showResult=function(){return resultEl.removeClass("hidden")},hideResult=function(){return resultEl.addClass("hidden")},spinnerEl=$el.find(".spin"),showSpinner=function(){return spinnerEl.removeClass("hidden")},hideSpinner=function(){return spinnerEl.addClass("hidden")},resultTitleEl=$el.find(".result-title"),setLoadingTitle=function(){return resultTitleEl.html("We are generating your dump file")},setAsyncTitle=function(){return resultTitleEl.html("We are generating your dump file")},setSyncTitle=function(){return resultTitleEl.html("Your dump file ir ready!")},resultMessageEl=$el.find(".result-message "),setLoadingMessage=function(){return resultMessageEl.html("Please don't close this page.")},setAsyncMessage=function(){return resultMessageEl.html("We will send you an email when ready.")},setSyncMessage=function(url){return resultMessageEl.html("If the download doesn't start automatically click here.")},showLoadingMode=function(){return showSpinner(),setLoadingTitle(),setLoadingMessage(),hideButtons(),showResult()},showExportResultAsyncMode=function(){return hideSpinner(),setAsyncTitle(),setAsyncMessage()},showExportResultSyncMode=function(url){return hideSpinner(),setSyncTitle(),setSyncMessage(url)},showErrorMode=function(){return hideSpinner(),hideResult(),showButtons()},$el.on("click","a.button-export",debounce(2e3,function(){return function(event){var onError,onSuccess;return event.preventDefault(),onSuccess=function(result){var dumpUrl;return 202===result.status?showExportResultAsyncMode():(dumpUrl=result.data.url,showExportResultSyncMode(dumpUrl),$window.open(dumpUrl,"_blank"))},onError=function(result){var errorMsg,_ref;return showErrorMode(),errorMsg="Our oompa loompas have some problems generasting your dump. Please try again. ",429===result.status?errorMsg="Sorry, our oompa loompas are very busy right now. Please try again in a few minutes. ":(null!=(_ref=result.data)?_ref._error_message:void 0)&&(errorMsg="Our oompa loompas have some problems generasting your dump: "+result.data._error_message),$confirm.notify("error",errorMsg)},showLoadingMode(),$rs.projects["export"]($scope.projectId).then(onSuccess,onError)}}(this)))},{link:link}},module.directive("tgProjectExport",["$window","$tgResources","$tgConfirm",ProjectExportDirective])}.call(this),function(){var ColorSelectionDirective,ProjectValuesController,ProjectValuesDirective,bindOnce,debounce,groupBy,joinStr,mixOf,module,taiga,toString,trim,__bind=function(fn,me){return function(){return fn.apply(me,arguments)}},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,trim=this.taiga.trim,toString=this.taiga.toString,joinStr=this.taiga.joinStr,groupBy=this.taiga.groupBy,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaAdmin"),ProjectValuesController=function(_super){function ProjectValuesController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,this.moveValue=__bind(this.moveValue,this),this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Project values - "+_this.scope.sectionName+" - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("admin:project-values:move",this.moveValue)}return __extends(ProjectValuesController,_super),ProjectValuesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],ProjectValuesController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},ProjectValuesController.prototype.loadValues=function(){return this.rs[this.scope.resource].listValues(this.scope.projectId,this.scope.type).then(function(_this){return function(values){return _this.scope.values=values,_this.scope.maxValueOrder=_.max(values,"order").order,values}}(this))},ProjectValuesController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.q.all([_this.loadProject(),_this.loadValues()])}}(this))},ProjectValuesController.prototype.moveValue=function(ctx,itemValue,itemIndex){var r,values;return values=this.scope.values,r=values.indexOf(itemValue),values.splice(r,1),values.splice(itemIndex,0,itemValue),_.each(values,function(value,index){return value.order=index}),this.repo.saveAll(values)},ProjectValuesController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("ProjectValuesController",ProjectValuesController),ProjectValuesDirective=function($log,$repo,$confirm,$location,animationFrame){var link,linkDragAndDrop,linkValue;return linkDragAndDrop=function($scope,$el){var itemEl,newParentScope,oldParentScope,tdom;return oldParentScope=null,newParentScope=null,itemEl=null,tdom=$el.find(".sortable"),tdom.sortable({handle:".row.table-main.visualization",dropOnEmpty:!0,connectWith:".project-values-body",revert:400,axis:"y"}),tdom.on("sortstop",function(event,ui){var itemIndex,itemValue;return itemEl=ui.item,itemValue=itemEl.scope().value,itemIndex=itemEl.index(),$scope.$broadcast("admin:project-values:move",itemValue,itemIndex)}),$scope.$on("$destroy",function(){return $el.off()})},linkValue=function($scope,$el,$attrs){var $ctrl,cancel,goToBottomList,initializeNewValue,saveValue,submit,valueType;return $ctrl=$el.controller(),valueType=$attrs.type,initializeNewValue=function(){return $scope.newValue={name:"",is_closed:!1,is_archived:!1}},initializeNewValue(),goToBottomList=function(){return function(focus){var table;return null==focus&&(focus=!1),table=$el.find(".table-main"),$(document.body).scrollTop(table.offset().top+table.height()),focus?$(".new-value input").focus():void 0}}(this),submit=debounce(2e3,function(){return function(){var promise;return promise=$repo.save($scope.project),promise.then(function(){return $confirm.notify("success")}),promise.then(null,function(data){return $confirm.notify("error",data._error_message)})}}(this)),saveValue=debounce(2e3,function(target){var form,promise,value;return form=target.parents("form").checksley(),form.validate()?(value=target.scope().value,promise=$repo.save(value),promise.then(function(){return function(){var row;return row=target.parents(".row.table-main"),row.addClass("hidden"),row.siblings(".visualization").removeClass("hidden")}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0}),cancel=function(target){var row,value;return row=target.parents(".row.table-main"),value=target.scope().value,$scope.$apply(function(){return row.addClass("hidden"),value.revert(),row.siblings(".visualization").removeClass("hidden")})},$el.on("submit","form",function(event){return event.preventDefault(),submit()}),$el.on("click","form a.button-green",function(event){return event.preventDefault(),submit()}),$el.on("click",".show-add-new",function(event){return event.preventDefault(),$el.find(".new-value").removeClass("hidden"),goToBottomList(!0)}),$el.on("click",".add-new",debounce(2e3,function(event){var form,promise;return event.preventDefault(),form=$el.find(".new-value").parents("form").checksley(),form.validate()?($scope.newValue.project=$scope.project.id,$scope.newValue.order=$scope.maxValueOrder?$scope.maxValueOrder+1:1,promise=$repo.create(valueType,$scope.newValue),promise.then(function(){return function(){return $ctrl.loadValues().then(function(){return animationFrame.add(function(){return goToBottomList()})}),$el.find(".new-value").addClass("hidden"),initializeNewValue()}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0})),$el.on("click",".delete-new",function(event){return event.preventDefault(),$el.find(".new-value").hide(),initializeNewValue()}),$el.on("click",".edit-value",function(event){var editionRow,row,target;return event.preventDefault(),target=angular.element(event.currentTarget),row=target.parents(".row.table-main"),row.addClass("hidden"),editionRow=row.siblings(".edition"),editionRow.removeClass("hidden"),editionRow.find("input:visible").first().focus().select()}),$el.on("keyup",".edition input",function(event){var target;return 13===event.keyCode?(target=angular.element(event.currentTarget),saveValue(target)):27===event.keyCode?(target=angular.element(event.currentTarget),cancel(target)):void 0}),$el.on("click",".save",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),saveValue(target)}),$el.on("click",".cancel",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),cancel(target)}),$el.on("click",".delete-value",function(event){var choices,replacement,subtitle,target,title,value;return event.preventDefault(),target=angular.element(event.currentTarget),value=target.scope().value,choices={},_.each($scope.values,function(option){return value.id!==option.id?choices[option.id]=option.name:void 0}),title="Delete value",subtitle=value.name,replacement="All items with this value will be changed to",0===_.keys(choices).length?$confirm.error("You can't delete all values."):$confirm.askChoice(title,subtitle,choices,replacement).then(function(response){var onError,onSucces;return onSucces=function(){return $ctrl.loadValues()["finally"](function(){return response.finish()})},onError=function(){return $confirm.notify("error")},$repo.remove(value,{moveTo:response.selected}).then(onSucces,onError)})})},link=function($scope,$el,$attrs){return linkDragAndDrop($scope,$el,$attrs),linkValue($scope,$el,$attrs),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgProjectValues",["$log","$tgRepo","$tgConfirm","$tgLocation","animationFrame",ProjectValuesDirective]),ColorSelectionDirective=function(){var link;return link=function($scope,$el,$attrs,$model){var $ctrl;return $ctrl=$el.controller(),$scope.$watch($attrs.ngModel,function(element){return $scope.color=element.color}),$el.on("click",".current-color",function(event){var body,target;return event.preventDefault(),event.stopPropagation(),target=angular.element(event.currentTarget),$el.find(".select-color").hide(),target.siblings(".select-color").show(),body=angular.element("body"),body.on("click",function(){return function(event){return 0===angular.element(event.target).parent(".select-color").length?($el.find(".select-color").hide(),body.unbind("click")):void 0}}(this))}),$el.on("click",".select-color .color",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),$scope.$apply(function(){return $model.$modelValue.color=target.data("color")}),$el.find(".select-color").hide()}),$el.on("click",".select-color .selected-color",function(event){return event.preventDefault(),$scope.$apply(function(){return $model.$modelValue.color=$scope.color}),$el.find(".select-color").hide()}),$scope.$on("$destroy",function(){return $el.off()})},{link:link,require:"ngModel"}},module.directive("tgColorSelection",ColorSelectionDirective)}.call(this),function(){var EditRoleDirective,NewRoleDirective,RolePermissionsDirective,RolesController,RolesDirective,bindMethods,bindOnce,debounce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child},__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1};taiga=this.taiga,mixOf=this.taiga.mixOf,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,bindMethods=this.taiga.bindMethods,module=angular.module("taigaAdmin"),RolesController=function(_super){function RolesController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,appTitle){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Permissions",this.scope.project={},this.scope.anyComputableRole=!0,promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Roles - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(RolesController,_super),RolesController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$appTitle"],RolesController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.anyComputableRole=_.some(_.map(project.roles,function(point){return point.computable})),project}}(this))},RolesController.prototype.loadRoles=function(){return this.rs.roles.list(this.scope.projectId).then(function(_this){return function(data){return _this.scope.roles=data,_this.scope.role=_this.scope.roles[0],data}}(this))},RolesController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadUsersAndRoles()}}(this)).then(function(_this){return function(){return _this.loadRoles()}}(this))},RolesController.prototype.setRole=function(role){return this.scope.role=role,this.scope.$broadcast("role:changed",this.scope.role)},RolesController.prototype["delete"]=function(){var choices,replacement,role,subtitle,title,warning,_i,_len,_ref;for(title="Delete Role",subtitle=this.scope.role.name,replacement="All the users with this role will be moved to",warning="Be careful, all role estimations will be removed",choices={},_ref=this.scope.roles,_i=0,_len=_ref.length;_len>_i;_i++)role=_ref[_i],role.id!==this.scope.role.id&&(choices[role.id]=role.name);return 0===_.keys(choices).length?this.confirm.error("You can't delete all values."):this.confirm.askChoice(title,subtitle,choices,replacement,warning).then(function(_this){return function(response){var promise;return promise=_this.repo.remove(_this.scope.role,{moveTo:response.selected}),promise.then(function(){return _this.loadProject(),_this.loadRoles()["finally"](function(){return response.finish()})}),promise.then(null,function(){return _this.confirm.notify("error")})}}(this))},RolesController.prototype.setComputable=debounce(2e3,function(){var onError,onSuccess;return onSuccess=function(_this){return function(){return _this.confirm.notify("success"),_this.loadProject()}}(this),onError=function(_this){return function(){return _this.confirm.notify("error"),_this.scope.role.revert()}}(this),this.repo.save(this.scope.role).then(onSuccess,onError)}),RolesController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("RolesController",RolesController),EditRoleDirective=function($repo,$confirm){var link;return link=function($scope,$el){var submit,toggleView;return toggleView=function(){return $el.find(".total").toggle(),$el.find(".edit-role").toggle()},submit=function(){var promise;return $scope.role.name=$el.find("input").val(),promise=$repo.save($scope.role),promise.then(function(){return $confirm.notify("success")}),promise.then(null,function(){return $confirm.notify("error")}),toggleView()},$el.on("click","a.icon-edit",function(){return toggleView(),$el.find("input").focus(),$el.find("input").val($scope.role.name)}),$el.on("click","a.save",submit),$el.on("keyup","input",function(event){return 13===event.keyCode?submit():27===event.keyCode?toggleView():void 0}),$scope.$on("role:changed",function(){return $el.find(".edit-role").is(":visible")?toggleView():void 0}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgEditRole",["$tgRepo","$tgConfirm",EditRoleDirective]),RolesDirective=function(){var link;return link=function($scope,$el){var $ctrl;return $ctrl=$el.controller(),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgRoles",RolesDirective),NewRoleDirective=function($tgrepo,$confirm){var DEFAULT_PERMISSIONS,link;return DEFAULT_PERMISSIONS=["view_project","view_milestones","view_us","view_tasks","view_issues"],link=function($scope,$el){var $ctrl;return $ctrl=$el.controller(),$scope.$on("$destroy",function(){return $el.off()}),$el.on("click","a.add-button",function(event){return event.preventDefault(),$el.find(".new").removeClass("hidden"),$el.find(".new").focus(),$el.find(".add-button").hide()}),$el.on("keyup",".new",function(event){var newRole,onError,onSuccess,target;return event.preventDefault(),13===event.keyCode?(target=angular.element(event.currentTarget),newRole={project:$scope.projectId,name:target.val(),permissions:DEFAULT_PERMISSIONS,order:_.max($scope.roles,function(r){return r.order}).order+1,computable:!1},$el.find(".new").addClass("hidden"),$el.find(".new").val(""),onSuccess=function(role){return $scope.roles.push(role),$ctrl.setRole(role),$el.find(".add-button").show(),$ctrl.loadProject()},onError=function(){return $confirm.notify("error")},$tgrepo.create("roles",newRole).then(onSuccess,onError)):27===event.keyCode?(target=angular.element(event.currentTarget),$el.find(".new").addClass("hidden"),$el.find(".new").val(""),$el.find(".add-button").show()):void 0})},{link:link}},module.directive("tgNewRole",["$tgRepo","$tgConfirm",NewRoleDirective]),RolePermissionsDirective=function($rootscope,$repo,$confirm){var baseTemplate,categoryTemplate,link,resumeTemplate;return resumeTemplate=_.template('
    <%- category.name %>
    \n
    \n
    <%- category.activePermissions %>/<%- category.permissions.length %>
    \n <% _.each(category.permissions, function(permission) { %>\n
    \n <% }) %>\n
    \n
    '),categoryTemplate=_.template('
    \n
    \n
    \n
    \n
    \n <% _.each(category.permissions, function(permission) { %>\n
    \n <%- permission.description %>\n
    \n checked="checked"<% } %>/>\n
    \n Yes\n No\n
    \n
    \n <% }) %>\n
    \n
    \n
    '),baseTemplate=_.template('
    '),link=function($scope,$el,$attrs){var $ctrl,generateCategoriesFromRole,renderCategory,renderPermissions,renderResume;return $ctrl=$el.controller(),generateCategoriesFromRole=function(role){var categories,issuePermissions,milestonePermissions,setActivePermissions,setActivePermissionsPerCategory,taskPermissions,userStoryPermissions,wikiPermissions;return setActivePermissions=function(permissions){return _.map(permissions,function(x){var _ref;return _.extend({},x,{active:(_ref=x.key,__indexOf.call(role.permissions,_ref)>=0)})})},setActivePermissionsPerCategory=function(category){return _.map(category,function(x){return _.extend({},x,{activePermissions:_.filter(x.permissions,"active").length})})},categories=[],milestonePermissions=[{key:"view_milestones",description:"View sprints"},{key:"add_milestone",description:"Add sprint"},{key:"modify_milestone",description:"Modify sprint"},{key:"delete_milestone",description:"Delete sprint"}],categories.push({name:"Sprints",permissions:setActivePermissions(milestonePermissions)}),userStoryPermissions=[{key:"view_us",description:"View user story"},{key:"add_us",description:"Add user story"},{key:"modify_us",description:"Modify user story"},{key:"delete_us",description:"Delete user story"}],categories.push({name:"User Stories",permissions:setActivePermissions(userStoryPermissions)}),taskPermissions=[{key:"view_tasks",description:"View tasks"},{key:"add_task",description:"Add task"},{key:"modify_task",description:"Modify task"},{key:"delete_task",description:"Delete task"}],categories.push({name:"Tasks",permissions:setActivePermissions(taskPermissions)}),issuePermissions=[{key:"view_issues",description:"View issues"},{key:"add_issue",description:"Add issue"},{key:"modify_issue",description:"Modify issue"},{key:"delete_issue",description:"Delete issue"}],categories.push({name:"Issues",permissions:setActivePermissions(issuePermissions)}),wikiPermissions=[{key:"view_wiki_pages",description:"View wiki pages"},{key:"add_wiki_page",description:"Add wiki page"},{key:"modify_wiki_page",description:"Modify wiki page"},{key:"delete_wiki_page",description:"Delete wiki page"},{key:"view_wiki_links",description:"View wiki links"},{key:"add_wiki_link",description:"Add wiki link"},{key:"delete_wiki_link",description:"Delete wiki link"}],categories.push({name:"Wiki",permissions:setActivePermissions(wikiPermissions)}),setActivePermissionsPerCategory(categories)},renderResume=function(element,category){return element.find(".resume").html(resumeTemplate({category:category}))},renderCategory=function(category,index){var html;return html=categoryTemplate({category:category,index:index}),html=angular.element(html),renderResume(html,category),html},renderPermissions=function(){var html;return $el.off(),html=baseTemplate(),_.each(generateCategoriesFromRole($scope.role),function(category,index){return html=angular.element(html).append(renderCategory(category,index))}),$el.html(html),$el.on("click",".resume",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),target.next().toggleClass("open")}),$el.on("change",".category-item input",function(event){var getActivePermissions,onError,onSuccess,target;return getActivePermissions=function(){var activePermissions;return activePermissions=_.filter($el.find(".category-item input"),function(t){return angular.element(t).is(":checked")}),activePermissions=_.sortBy(_.map(activePermissions,function(t){var permission;return permission=angular.element(t).parents(".category-item").data("id")})),activePermissions.push("view_project"),activePermissions},target=angular.element(event.currentTarget),$scope.role.permissions=getActivePermissions(),onSuccess=function(role){var categories,categoryId;return categories=generateCategoriesFromRole(role),categoryId=target.parents(".category-config").data("id"),renderResume(target.parents(".category-config"),categories[categoryId]),$rootscope.$broadcast("projects:reload"),$confirm.notify("success"),$ctrl.loadProject()},onError=function(){return $confirm.notify("error"),target.prop("checked",!target.prop("checked")),$scope.role.permissions=getActivePermissions()},$repo.save($scope.role).then(onSuccess,onError)})},$scope.$on("$destroy",function(){return $el.off()}),$scope.$on("role:changed",function(){return renderPermissions()}),bindOnce($scope,$attrs.ngModel,renderPermissions)},{link:link}},module.directive("tgRolePermissions",["$rootScope","$tgRepo","$tgConfirm",RolePermissionsDirective]) +}.call(this),function(){var BitbucketController,BitbucketWebhooksDirective,GithubController,GithubWebhooksDirective,GitlabController,GitlabWebhooksDirective,NewWebhookDirective,SelectInputText,ValidOriginIpsDirective,WebhookDirective,WebhooksController,bindMethods,debounce,mixOf,module,taiga,timeout,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindMethods=this.taiga.bindMethods,debounce=this.taiga.debounce,timeout=this.taiga.timeout,module=angular.module("taigaAdmin"),WebhooksController=function(_super){function WebhooksController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Webhooks",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Webhooks - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("webhooks:reload",this.loadWebhooks)}return __extends(WebhooksController,_super),WebhooksController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],WebhooksController.prototype.loadWebhooks=function(){return this.rs.webhooks.list(this.scope.projectId).then(function(_this){return function(webhooks){return _this.scope.webhooks=webhooks}}(this))},WebhooksController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},WebhooksController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadWebhooks()}}(this))},WebhooksController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("WebhooksController",WebhooksController),WebhookDirective=function($rs,$repo,$confirm){var link;return link=function($scope,$el,$attrs){var cancel,openHistory,save,showEditMode,showVisualizationMode,updateLogs,updateShowHideHistoryText,webhook;return webhook=$scope.$eval($attrs.tgWebhook),updateLogs=function(){return $rs.webhooklogs.list(webhook.id).then(function(){return function(webhooklogs){var log,_i,_len,_ref;for(_i=0,_len=webhooklogs.length;_len>_i;_i++)log=webhooklogs[_i],log.validStatus=200<=(_ref=log.status)&&300>_ref,log.prettySentHeaders=_.map(_.pairs(log.request_headers),function(_arg){var header,value;return header=_arg[0],value=_arg[1],""+header+": "+value}).join("\n"),log.prettySentData=JSON.stringify(log.request_data.data,void 0,2),log.prettyDate=moment(log.created).format("DD MMM YYYY [at] hh:mm:ss");return webhook.logs_counter=webhooklogs.length,webhook.logs=webhooklogs,updateShowHideHistoryText()}}(this))},updateShowHideHistoryText=function(){var historyElement,textElement;return textElement=$el.find(".toggle-history"),historyElement=textElement.parents(".single-webhook-wrapper").find(".webhooks-history"),textElement.text(historyElement.hasClass("open")?"(Hide history)":"(Show history)")},showVisualizationMode=function(){return $el.find(".edition-mode").addClass("hidden"),$el.find(".visualization-mode").removeClass("hidden")},showEditMode=function(){return $el.find(".visualization-mode").addClass("hidden"),$el.find(".edition-mode").removeClass("hidden")},openHistory=function(){return $el.find(".webhooks-history").addClass("open")},cancel=function(){return showVisualizationMode(),$scope.$apply(function(){return webhook.revert()})},save=debounce(2e3,function(target){var form,promise,value;return form=target.parents("form").checksley(),form.validate()?(value=target.scope().value,promise=$repo.save(webhook),promise.then(function(){return function(){return showVisualizationMode()}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0}),$el.on("click",".test-webhook",function(){return openHistory(),$rs.webhooks.test(webhook.id).then(function(){return function(){return updateLogs()}}(this))}),$el.on("click",".edit-webhook",function(){return showEditMode()}),$el.on("click",".cancel-existing",function(){return cancel()}),$el.on("click",".edit-existing",function(event){var target;return event.preventDefault(),target=angular.element(event.currentTarget),save(target)}),$el.on("keyup",".edition-mode input",function(event){var target;return 13===event.keyCode?(target=angular.element(event.currentTarget),saveWebhook(target)):27===event.keyCode?(target=angular.element(event.currentTarget),cancel(target)):void 0}),$el.on("click",".delete-webhook",function(){var message,title;return title="Delete webhook",message="Webhook '"+webhook.name+"'",$confirm.askOnDelete(title,message).then(function(){return function(finish){var onError,onSucces;return onSucces=function(){return finish(),$scope.$emit("webhooks:reload")},onError=function(){return finish(!1),$confirm.notify("error")},$repo.remove(webhook).then(onSucces,onError)}}(this))}),$el.on("click",".toggle-history",function(event){var target;return target=angular.element(event.currentTarget),null==webhook.logs||0===webhook.logs.length?updateLogs().then(function(){return timeout(0,function(){return $el.find(".webhooks-history").toggleClass("open"),updateShowHideHistoryText()})}):($el.find(".webhooks-history").toggleClass("open"),$scope.$apply(function(){return updateShowHideHistoryText()}))}),$el.on("click",".history-single",function(event){var target;return target=angular.element(event.currentTarget),target.toggleClass("history-single-open"),target.siblings(".history-single-response").toggleClass("open")}),$el.on("click",".resend-request",function(event){var log,target;return target=angular.element(event.currentTarget),log=target.data("log"),$rs.webhooklogs.resend(log).then(function(){return function(){return updateLogs()}}(this))})},{link:link}},module.directive("tgWebhook",["$tgResources","$tgRepo","$tgConfirm","$tgLoading",WebhookDirective]),NewWebhookDirective=function($rs,$repo,$confirm){var link;return link=function($scope,$el,$attrs){var addWebhookDOMNode,formDOMNode,initializeNewValue,webhook;return webhook=$scope.$eval($attrs.tgWebhook),formDOMNode=$el.find(".new-webhook-form"),addWebhookDOMNode=$el.find(".add-webhook"),initializeNewValue=function(){return $scope.newValue={name:"",url:"",key:""}},initializeNewValue(),$scope.$watch("webhooks",function(webhooks){return null!=webhooks?0===webhooks.length?(formDOMNode.removeClass("hidden"),addWebhookDOMNode.addClass("hidden"),formDOMNode.find("input")[0].focus()):(formDOMNode.addClass("hidden"),addWebhookDOMNode.removeClass("hidden")):void 0}),formDOMNode.on("click",".add-new",debounce(2e3,function(event){var form,promise;return event.preventDefault(),form=formDOMNode.checksley(),form.validate()?($scope.newValue.project=$scope.project.id,promise=$repo.create("webhooks",$scope.newValue),promise.then(function(){return function(){return $scope.$emit("webhooks:reload"),initializeNewValue()}}(this)),promise.then(null,function(data){return $confirm.notify("error"),form.setErrors(data)})):void 0})),formDOMNode.on("click",".cancel-new",function(){return $scope.$apply(function(){return initializeNewValue()})}),addWebhookDOMNode.on("click",function(){return formDOMNode.removeClass("hidden"),formDOMNode.find("input")[0].focus()})},{link:link}},module.directive("tgNewWebhook",["$tgResources","$tgRepo","$tgConfirm","$tgLoading",NewWebhookDirective]),GithubController=function(_super){function GithubController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Github",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Github - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(GithubController,_super),GithubController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],GithubController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"github").then(function(_this){return function(github){return _this.scope.github=github}}(this))},GithubController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},GithubController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},GithubController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("GithubController",GithubController),GitlabController=function(_super){function GitlabController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Gitlab",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Gitlab - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:modules:reload",function(_this){return function(){return _this.loadModules()}}(this))}return __extends(GitlabController,_super),GitlabController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],GitlabController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"gitlab").then(function(_this){return function(gitlab){return _this.scope.gitlab=gitlab}}(this))},GitlabController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},GitlabController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},GitlabController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("GitlabController",GitlabController),BitbucketController=function(_super){function BitbucketController(scope,repo,rs,params,appTitle){var promise;this.scope=scope,this.repo=repo,this.rs=rs,this.params=params,this.appTitle=appTitle,bindMethods(this),this.scope.sectionName="Bitbucket",this.scope.project={},promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set("Bitbucket - "+_this.scope.project.name)}}(this)),promise.then(null,this.onInitialDataError.bind(this)),this.scope.$on("project:modules:reload",function(_this){return function(){return _this.loadModules()}}(this))}return __extends(BitbucketController,_super),BitbucketController.$inject=["$scope","$tgRepo","$tgResources","$routeParams","$appTitle"],BitbucketController.prototype.loadModules=function(){return this.rs.modules.list(this.scope.projectId,"bitbucket").then(function(_this){return function(bitbucket){return _this.scope.bitbucket=bitbucket}}(this))},BitbucketController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},BitbucketController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadModules()}}(this))},BitbucketController}(mixOf(taiga.Controller,taiga.PageMixin,taiga.FiltersMixin)),module.controller("BitbucketController",BitbucketController),SelectInputText=function(){var link;return link=function($scope,$el){return $el.on("click",".select-input-content",function(){return $el.find("input").select(),$el.find(".help-copy").addClass("visible")})},{link:link}},module.directive("tgSelectInputText",SelectInputText),GithubWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.github,"github"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgGithubWebhooks",["$tgRepo","$tgConfirm","$tgLoading",GithubWebhooksDirective]),GitlabWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.gitlab,"gitlab"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success"),$scope.$emit("project:modules:reload")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgGitlabWebhooks",["$tgRepo","$tgConfirm","$tgLoading",GitlabWebhooksDirective]),BitbucketWebhooksDirective=function($repo,$confirm,$loading){var link;return link=function($scope,$el){var form,submit,submitButton;return form=$el.find("form").checksley({onlyOneErrorElement:!0}),submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.saveAttribute($scope.bitbucket,"bitbucket"),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success"),$scope.$emit("project:modules:reload")}),promise.then(null,function(data){return $loading.finish(submitButton),form.setErrors(data),data._error_message?$confirm.notify("error",data._error_message):void 0})):void 0}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit)},{link:link}},module.directive("tgBitbucketWebhooks",["$tgRepo","$tgConfirm","$tgLoading",BitbucketWebhooksDirective]),ValidOriginIpsDirective=function(){var link;return link=function($scope,$el,$attrs,$ngModel){return $ngModel.$parsers.push(function(value){return value=$.trim(value),""===value?[]:value.split(",")})},{link:link,restrict:"EA",require:"ngModel"}},module.directive("tgValidOriginIps",ValidOriginIpsDirective)}.call(this),function(){var CreateProject,DeleteProjectDirective,bindOnce,debounce,module,taiga,timeout;taiga=this.taiga,bindOnce=this.taiga.bindOnce,timeout=this.taiga.timeout,debounce=this.taiga.debounce,module=angular.module("taigaProject"),CreateProject=function($rootscope,$repo,$confirm,$location,$navurls,$rs,$projectUrl,$loading,lightboxService,$cacheFactory){var link;return link=function($scope,$el){var form,onErrorSubmit,onSuccessSubmit,submit,submitButton;return $scope.data={},$scope.templates=[],form=$el.find("form").checksley({onlyOneErrorElement:!0}),onSuccessSubmit=function(response){return $cacheFactory.get("$http").removeAll(),$loading.finish(submitButton),$rootscope.$broadcast("projects:reload"),$confirm.notify("success","Success"),$location.url($projectUrl.get(response)),lightboxService.close($el)},onErrorSubmit=function(response){var error_field,error_step,selectors,_i,_len,_ref;for($loading.finish(submitButton),form.setErrors(response),selectors=[],_ref=_.keys(response),_i=0,_len=_ref.length;_len>_i;_i++)error_field=_ref[_i],selectors.push("[name="+error_field+"]");return $el.find(".active").removeClass("active"),error_step=$el.find(selectors.join(",")).first().parents(".wizard-step"),error_step.addClass("active"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(error_step.data("step"))},submit=function(){return function(event){var promise;return event.preventDefault(),form.validate()?($loading.start(submitButton),promise=$repo.create("projects",$scope.data),promise.then(onSuccessSubmit,onErrorSubmit)):void 0}}(this),$scope.$on("projects:create",function(){return $scope.data={total_story_points:100,total_milestones:5},$scope.templates.length?$scope.data.creation_template=_.head(_.filter($scope.templates,function(x){return"scrum"===x.slug})).id:$rs.projects.templates().then(function(){return function(result){return $scope.templates=result,$scope.data.creation_template=_.head(_.filter($scope.templates,function(x){return"scrum"===x.slug})).id}}(this)),$el.find(".active").removeClass("active"),$el.find(".create-step1").addClass("active"),lightboxService.open($el),timeout(600,function(){return $el.find(".progress-bar").addClass("step1")})}),$el.on("click",".button-next",function(event){var current,field,next,step,valid,_i,_len,_ref;for(event.preventDefault(),current=$el.find(".active"),valid=!0,_ref=form.fields,_i=0,_len=_ref.length;_len>_i;_i++)field=_ref[_i],current.find("[name="+field.element.attr("name")+"]").length&&(valid=field.validate()!==!1&&valid);return valid?(next=current.next(),current.toggleClass("active"),next.toggleClass("active"),step=next.data("step"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(step)):void 0}),$el.on("click",".button-prev",function(event){var current,prev,step;return event.preventDefault(),current=$el.find(".active"),prev=current.prev(),current.toggleClass("active"),prev.toggleClass("active"),step=prev.data("step"),$el.find(".progress-bar").removeClass().addClass("progress-bar").addClass(step)}),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$el.on("click",".close",function(event){return event.preventDefault(),lightboxService.close($el)})},{link:link}},module.directive("tgLbCreateProject",["$rootScope","$tgRepo","$tgConfirm","$location","$tgNavUrls","$tgResources","$projectUrl","$tgLoading","lightboxService","$cacheFactory",CreateProject]),DeleteProjectDirective=function($repo,$rootscope,$auth,$location,$navUrls,$confirm,lightboxService,tgLoader){var link;return link=function($scope,$el){var projectToDelete,submit;return projectToDelete=null,$scope.$on("deletelightbox:new",function(ctx,project){return lightboxService.open($el),projectToDelete=project}),$scope.$on("$destroy",function(){return $el.off()}),submit=function(){var promise;return tgLoader.start(),lightboxService.close($el),promise=$repo.remove(projectToDelete),promise.then(function(){return tgLoader.pageLoaded(),$rootscope.$broadcast("projects:reload"),$location.path($navUrls.resolve("home")),$confirm.notify("success")}),promise.then(null,function(){return $confirm.notify("error"),lightboxService.close($el)})},$el.on("click",".button-red",function(event){return event.preventDefault(),lightboxService.close($el)}),$el.on("click",".button-green",function(event){return event.preventDefault(),submit()})},{link:link}},module.directive("tgLbDeleteProject",["$tgRepo","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","$tgConfirm","lightboxService","tgLoader",DeleteProjectDirective])}.call(this),function(){var ProjectController,ProjectsController,ProjectsListDirective,ProjectsPaginationDirective,bindOnce,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,module=angular.module("taigaProject"),bindOnce=this.taiga.bindOnce,ProjectsController=function(_super){function ProjectsController(scope,q,rs,rootscope,navUrls,auth,location,appTitle,projectUrl,tgLoader){var promise;this.scope=scope,this.q=q,this.rs=rs,this.rootscope=rootscope,this.navUrls=navUrls,this.auth=auth,this.location=location,this.appTitle=appTitle,this.projectUrl=projectUrl,this.appTitle.set("Projects"),this.auth.isAuthenticated()||this.location.path(this.navUrls.resolve("login")),this.user=this.auth.getUser(),this.projects=[],promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.scope.$emit("projects:loaded")}}(this)),promise.then(null,this.onInitialDataError.bind(this)),promise["finally"](tgLoader.pageLoaded)}return __extends(ProjectsController,_super),ProjectsController.$inject=["$scope","$q","$tgResources","$rootScope","$tgNavUrls","$tgAuth","$tgLocation","$appTitle","$projectUrl","tgLoader"],ProjectsController.prototype.loadInitialData=function(){return this.rs.projects.list().then(function(_this){return function(projects){var project,_i,_len;for(_this.projects={recents:projects.slice(0,8),all:projects},_i=0,_len=projects.length;_len>_i;_i++)project=projects[_i],project.url=_this.projectUrl.get(project);return projects}}(this))},ProjectsController.prototype.newProject=function(){return this.rootscope.$broadcast("projects:create")},ProjectsController.prototype.logout=function(){return this.auth.logout(),this.location.path(this.navUrls.resolve("login"))},ProjectsController}(taiga.Controller),module.controller("ProjectsController",ProjectsController),ProjectController=function(_super){function ProjectController(scope,rs,repo,params,q,rootscope,appTitle,location,navUrls){var promise;this.scope=scope,this.rs=rs,this.repo=repo,this.params=params,this.q=q,this.rootscope=rootscope,this.appTitle=appTitle,this.location=location,this.navUrls=navUrls,promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.project.name),_this.scope.$emit("regenerate:project-pagination")}}(this)),promise.then(null,this.onInitialDataError.bind(this))}return __extends(ProjectController,_super),ProjectController.$inject=["$scope","$tgResources","$tgRepo","$routeParams","$q","$rootScope","$appTitle","$tgLocation","$tgNavUrls"],ProjectController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadPageData()}}(this)).then(function(_this){return function(){return _this.scope.$emit("project:loaded",_this.scope.project)}}(this))},ProjectController.prototype.loadPageData=function(){return this.q.all([this.loadProjectStats(),this.loadProject()])},ProjectController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,project}}(this))},ProjectController.prototype.loadProjectStats=function(){return this.rs.projects.stats(this.scope.projectId).then(function(_this){return function(stats){return _this.scope.stats=stats,stats}}(this))},ProjectController}(taiga.Controller),module.controller("ProjectController",ProjectController),ProjectsPaginationDirective=function(){var link;return link=function($scope,$el){var checkButtonVisibility,container,containerSize,hasNextPage,hasPagination,hasPrevPage,hide,nextBtn,nextPage,pageSize,prevBtn,prevPage,remove,render,visible;return prevBtn=$el.find(".v-pagination-previous"),nextBtn=$el.find(".v-pagination-next"),container=$el.find("ul"),pageSize=0,containerSize=0,render=function(){return pageSize=$el.find(".v-pagination-list").height(),container.find("li").length&&hasPagination()?(hasNextPage()?visible(nextBtn):hide(nextBtn),hasPrevPage()?visible(prevBtn):hide(prevBtn)):remove()},hasPagination=function(){return containerSize=container.height(),containerSize>pageSize},hasPrevPage=function(top){return null==top&&(top=-parseInt(container.css("top"),10)||0),0!==top},hasNextPage=function(top){return containerSize=container.height(),top||(top=-parseInt(container.css("top"),10)||0),containerSize>pageSize&&containerSize>top+pageSize},nextPage=function(callback){var lastLi,maxTop,newTop,top;return top=parseInt(container.css("top"),10),newTop=top-pageSize,lastLi=$el.find(".v-pagination-list li:last-child"),maxTop=-(lastLi.position().top+lastLi.outerHeight()-pageSize),maxTop>newTop&&(newTop=maxTop),container.animate({top:newTop},callback),newTop},prevPage=function(callback){var newTop,top;return top=parseInt(container.css("top"),10),newTop=top+pageSize,newTop>0&&(newTop=0),container.animate({top:newTop},callback),newTop},visible=function(element){return element.css("visibility","visible")},hide=function(element){return element.css("visibility","hidden")},checkButtonVisibility=function(){},remove=function(){return container.css("top",0),hide(prevBtn),hide(nextBtn)},$el.on("click",".v-pagination-previous",function(event){var newTop;return event.preventDefault(),container.is(":animated")?void 0:(visible(nextBtn),newTop=prevPage(),hasPrevPage(newTop)?void 0:hide(prevBtn))}),$el.on("click",".v-pagination-next",function(event){var newTop;return event.preventDefault(),container.is(":animated")?void 0:(visible(prevBtn),newTop=-nextPage(),hasNextPage(newTop)?void 0:hide(nextBtn))}),$scope.$on("regenerate:project-pagination",function(){return remove(),render()}),$(window).on("resize.projects-pagination",render),$scope.$on("$destroy",function(){return $(window).off("resize.projects-pagination")})},{link:link}},module.directive("tgProjectsPagination",["$timeout",ProjectsPaginationDirective]),ProjectsListDirective=function($compile,$template){var link,template;return template=$template.get("project/project-list.html",!0),link=function($scope,$el){var render;return render=function(projects){return $el.html($compile(template({projects:projects}))($scope)),$scope.$emit("regenerate:project-pagination")},$scope.$watch("projects",function(projects){return null!=projects?render(projects):void 0})},{link:link}},module.directive("tgProjectsList",["$compile","$tgTemplate",ProjectsListDirective])}.call(this),function(){var BindHtmlDirective,BindOnceAltDirective,BindOnceBindDirective,BindOnceHrefDirective,BindOnceHtmlDirective,BindOnceRefDirective,BindOnceSrcDirective,BindOnceTitleDirective,BindTitleDirective,bindOnce,module;bindOnce=this.taiga.bindOnce,BindOnceBindDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoBind,function(val){return $el.text(val)})},{link:link}},BindOnceHtmlDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoHtml,function(val){return $el.html(val)})},{link:link}},BindOnceRefDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoRef,function(val){return $el.html("#"+val+" ")})},{link:link}},BindOnceSrcDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoSrc,function(val){return $el.attr("src",val)})},{link:link}},BindOnceHrefDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoHref,function(val){return $el.attr("href",val)})},{link:link}},BindOnceAltDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoAlt,function(val){return $el.attr("alt",val)})},{link:link}},BindOnceTitleDirective=function(){var link;return link=function($scope,$el,$attrs){return bindOnce($scope,$attrs.tgBoTitle,function(val){return $el.attr("title",val)})},{link:link}},BindTitleDirective=function(){var link;return link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgTitleHtml,function(val){return null!=val?$el.attr("title",val):void 0})},{link:link}},BindHtmlDirective=function(){var link;return link=function($scope,$el,$attrs){return $scope.$watch($attrs.tgBindHtml,function(val){return null!=val?$el.html(val):void 0})},{link:link}},module=angular.module("taigaBase"),module.directive("tgBoBind",BindOnceBindDirective),module.directive("tgBoHtml",BindOnceHtmlDirective),module.directive("tgBoRef",BindOnceRefDirective),module.directive("tgBoSrc",BindOnceSrcDirective),module.directive("tgBoHref",BindOnceHrefDirective),module.directive("tgBoAlt",BindOnceAltDirective),module.directive("tgBoTitle",BindOnceTitleDirective),module.directive("tgBindTitle",BindTitleDirective),module.directive("tgBindHtml",BindHtmlDirective)}.call(this),function(){var ConfigurationService,module;ConfigurationService=function(){function ConfigurationService(){this.config=window.taigaConfig}return ConfigurationService.prototype.get=function(key,defaultValue){return null==defaultValue&&(defaultValue=null),_.has(this.config,key)?this.config[key]:defaultValue},ConfigurationService}(),module=angular.module("taigaBase"),module.service("$tgConfig",ConfigurationService)}.call(this),function(){var ContribController,module,taigaContribPlugins,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taigaContribPlugins=this.taigaContribPlugins=this.taigaContribPlugins||[],ContribController=function(_super){function ContribController(rootScope,scope,params,repo,rs,confirm,appTitle){var promise;this.rootScope=rootScope,this.scope=scope,this.params=params,this.repo=repo,this.rs=rs,this.confirm=confirm,this.appTitle=appTitle,this.scope.currentPlugin=_.first(_.where(taigaContribPlugins,{slug:this.params.plugin})),this.scope.pluginTemplate="contrib/"+this.scope.currentPlugin.slug,this.scope.projectSlug=this.params.pslug,this.scope.adminPlugins=_.where(this.rootScope.contribPlugins,{type:"admin"}),promise=this.loadInitialData(),promise.then(function(_this){return function(){return _this.appTitle.set(_this.scope.project.name)}}(this)),promise.then(null,function(_this){return function(){return _this.confirm.notify("error")}}(this))}return __extends(ContribController,_super),ContribController.$inject=["$rootScope","$scope","$routeParams","$tgRepo","$tgResources","$tgConfirm","$appTitle"],ContribController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),_this.scope.$broadcast("project:loaded",project),project}}(this))},ContribController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data +}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},ContribController}(taiga.Controller),module=angular.module("taigaBase"),module.controller("ContribController",ContribController)}.call(this),function(){var FiltersStorageService,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,FiltersStorageService=function(_super){function FiltersStorageService(storage,params){this.storage=storage,this.params=params}return __extends(FiltersStorageService,_super),FiltersStorageService.$inject=["$tgStorage","$routeParams"],FiltersStorageService.prototype.generateHash=function(components){return null==components&&(components=[]),components=_.map(components,function(x){return JSON.stringify(x)}),hex_sha1(components.join(":"))},FiltersStorageService}(taiga.Service)}.call(this),function(){var HttpService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,HttpService=function(_super){function HttpService(http,q,storage){this.http=http,this.q=q,this.storage=storage,HttpService.__super__.constructor.call(this)}return __extends(HttpService,_super),HttpService.$inject=["$http","$q","$tgStorage"],HttpService.prototype.headers=function(){var token;return token=this.storage.get("token"),token?{Authorization:"Bearer "+token}:{}},HttpService.prototype.request=function(options){return options.headers=_.merge({},options.headers||{},this.headers()),_.isPlainObject(options.data)&&(options.data=JSON.stringify(options.data)),this.http(options)},HttpService.prototype.get=function(url,params,options){return options=_.merge({method:"GET",url:url},options),params&&(options.params=params),this.request(options)},HttpService.prototype.post=function(url,data,params,options){return options=_.merge({method:"POST",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype.put=function(url,data,params,options){return options=_.merge({method:"PUT",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype.patch=function(url,data,params,options){return options=_.merge({method:"PATCH",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService.prototype["delete"]=function(url,data,params,options){return options=_.merge({method:"DELETE",url:url},options),data&&(options.data=data),params&&(options.params=params),this.request(options)},HttpService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgHttp",HttpService)}.call(this),function(){var I18nDirective,I18nService,bindOnce,defaults,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,bindOnce=this.taiga.bindOnce,defaults={ns:"app",fallbackLng:"en",async:!1,lng:"en"},I18nService=function(_super){function I18nService(rootscope,localesEn){this.rootscope=rootscope,this.options=_.clone(defaults,!0),this.options.resStore={en:{app:localesEn}}}return __extends(I18nService,_super),I18nService.prototype.setLanguage=function(language){return i18n.setLng(language),this.rootscope.currentLang=language,this.rootscope.$broadcast("i18n:changeLang",language)},I18nService.prototype.initialize=function(){return i18n.init(this.options),this.rootscope.t=i18n.t},I18nService.prototype.t=function(path,opts){return i18n.t(path,opts)},I18nService}(taiga.Service),I18nDirective=function($rootscope,$i18n){var link;return link=function($scope,$el,$attrs){var ns,options,opts,v,values,_i,_len,_ref,_results;for(values=$attrs.tr.split(","),options=$attrs.trOpts||"{}",opts=$scope.$eval(options),_results=[],_i=0,_len=values.length;_len>_i;_i++)v=values[_i],-1===v.indexOf(":")?_results.push($el.html(_.escape($i18n.t(v,opts)))):(_ref=v.split(":"),ns=_ref[0],v=_ref[1],_results.push($el.attr(ns,_.escape($i18n.t(v,opts)))));return _results},{link:link,restrict:"A",scope:!1}},module=angular.module("taigaBase"),module.service("$tgI18n",["$rootScope","localesEn",I18nService]),module.directive("tr",["$rootScope","$tgI18n",I18nDirective])}.call(this),function(){var locationFactory,module;locationFactory=function($location,$route){return $location.noreload=function(scope){var lastRoute,un;return lastRoute=$route.current,un=scope.$on("$locationChangeSuccess",function(){return $route.current=lastRoute,un()}),$location},$location},module=angular.module("taigaBase"),module.factory("$tgLocation",["$location","$route","$rootScope",locationFactory])}.call(this),function(){var Model,ModelService,module,provider,taiga,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;l>i;i++)if(i in this&&this[i]===item)return i;return-1},__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};Model=function(){function Model(name,data,dataTypes){this._attrs=data,this._name=name,this._dataTypes=dataTypes,this.setAttrs(data),this.initialize()}return Model.prototype.clone=function(){var instance;return instance=new Model(this._name,this._attrs,this._dataTypes),instance._modifiedAttrs=this._modifiedAttrs,instance._isModified=this._isModified,instance},Model.prototype.applyCasts=function(){var attrName,castMethod,castName,_ref,_results;_ref=this._dataTypes,_results=[];for(attrName in _ref)castName=_ref[attrName],castMethod=service.casts[castName],castMethod&&_results.push(this._attrs[attrName]=castMethod(this._attrs[attrName]));return _results},Model.prototype.getIdAttrName=function(){return"id"},Model.prototype.getName=function(){return this._name},Model.prototype.getAttrs=function(patch){return null==patch&&(patch=!1),null!=this._attrs.version&&(this._modifiedAttrs.version=this._attrs.version),patch?_.extend({},this._modifiedAttrs):_.extend({},this._attrs,this._modifiedAttrs)},Model.prototype.setAttrs=function(attrs){return this._attrs=attrs,this._modifiedAttrs={},this.applyCasts(),this._isModified=!1},Model.prototype.setAttr=function(name,value){return this._modifiedAttrs[name]=value,this._isModified=!0},Model.prototype.initialize=function(){var getter,self,setter;return self=this,getter=function(name){return function(){return"string"==typeof name&&"__"===name.substr(0,2)?self[name]:__indexOf.call(_.keys(self._modifiedAttrs),name)<0?self._attrs[name]:self._modifiedAttrs[name]}},setter=function(name){return function(value){return"string"==typeof name&&"__"===name.substr(0,2)?void(self[name]=value):void(self._attrs[name]!==value?(self._modifiedAttrs[name]=value,self._isModified=!0):delete self._modifiedAttrs[name])}},_.each(this._attrs,function(value,name){var options;return options={get:getter(name),set:setter(name),enumerable:!0,configurable:!0},Object.defineProperty(self,name,options)})},Model.prototype.serialize=function(){var data;return data={data:_.clone(this._attrs),name:this._name},JSON.stringify(data)},Model.prototype.isModified=function(){return this._isModified},Model.prototype.isAttributeModified=function(attribute){return null!=this._modifiedAttrs[attribute]},Model.prototype.markSaved=function(){return this._isModified=!1,this._attrs=this.getAttrs(),this._modifiedAttrs={}},Model.prototype.revert=function(){return this._modifiedAttrs={},this._isModified=!1},Model.desSerialize=function(sdata){var ddata,model;return ddata=JSON.parse(sdata),model=new Model(ddata.url,ddata.data)},Model}(),taiga=this.taiga,ModelService=function(_super){function ModelService(q,urls,storage,http){this.q=q,this.urls=urls,this.storage=storage,this.http=http,ModelService.__super__.constructor.call(this)}return __extends(ModelService,_super),ModelService.$inject=["$q","$tgUrls","$tgStorage","$tgHttp"],ModelService}(taiga.Service),provider=function(){var service;return service={},service.make_model=function(name,data,cls,dataTypes){return null==cls&&(cls=Model),null==dataTypes&&(dataTypes={}),new cls(name,data,dataTypes)},service.cls=Model,service.casts={"int":function(value){return parseInt(value,10)},"float":function(value){return parseFloat(value,10)}},service},module=angular.module("taigaBase"),module.factory("$tgModel",["$q","$http","$tgUrls","$tgStorage",provider])}.call(this),function(){var NavigationUrlsDirective,NavigationUrlsService,bindOnce,module,taiga,trim,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,trim=this.taiga.trim,bindOnce=this.taiga.bindOnce,module=angular.module("taigaBase"),NavigationUrlsService=function(_super){function NavigationUrlsService(){this.urls={}}return __extends(NavigationUrlsService,_super),NavigationUrlsService.prototype.update=function(urls){return this.urls=_.merge({},this.urls,urls||{})},NavigationUrlsService.prototype.formatUrl=function(url,ctx){var replacer;return null==ctx&&(ctx={}),replacer=function(match){return match=trim(match,":"),ctx[match]||"undefined"},url.replace(/(:\w+)/g,replacer)},NavigationUrlsService.prototype.resolve=function(name,ctx){var url;return url=this.urls[name],url?ctx?this.formatUrl(url,ctx):url:""},NavigationUrlsService}(taiga.Service),module.service("$tgNavUrls",NavigationUrlsService),NavigationUrlsDirective=function($navurls,$auth,$q,$location){var bindOnceP,link,parseNav;return bindOnceP=function($scope,attr){var defered;return defered=$q.defer(),bindOnce($scope,attr,function(v){return defered.resolve(v)}),defered.promise},parseNav=function(data,$scope){var name,params,promises,values,_ref;return _ref=_.map(data.split(":"),trim),name=_ref[0],params=_ref[1],params=params?_.map(params.split(","),trim):[],values=_.map(params,function(x){return trim(x.split("=")[1])}),promises=_.map(values,function(x){return bindOnceP($scope,x)}),$q.all(promises).then(function(){var item,key,options,value,_i,_len,_ref1;for(options={},_i=0,_len=params.length;_len>_i;_i++)item=params[_i],_ref1=_.map(item.split("="),trim),key=_ref1[0],value=_ref1[1],options[key]=$scope.$eval(value);return[name,options]})},link=function($scope,$el,$attrs){return $el.is("a")&&$el.attr("href","#"),$el.on("mouseenter",function(event){var target;return target=$(event.currentTarget),target.data("fullUrl")?void 0:parseNav($attrs.tgNav,$scope).then(function(result){var fullUrl,name,options,url,user;return name=result[0],options=result[1],user=$auth.getUser(),user&&(options.user=user.username),url=$navurls.resolve(name),fullUrl=$navurls.formatUrl(url,options),target.data("fullUrl",fullUrl),target.is("a")&&target.attr("href",fullUrl),$el.on("click",function(event){if(event.preventDefault(),target=$(event.currentTarget),!target.hasClass("noclick"))switch(fullUrl=target.data("fullUrl"),event.which){case 1:return $location.url(fullUrl),$scope.$apply();case 2:return window.open(fullUrl)}})})}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgNav",["$tgNavUrls","$tgAuth","$q","$tgLocation",NavigationUrlsDirective])}.call(this),function(){var RepositoryService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,RepositoryService=function(_super){function RepositoryService(q,model,storage,http,urls){this.q=q,this.model=model,this.storage=storage,this.http=http,this.urls=urls,RepositoryService.__super__.constructor.call(this)}return __extends(RepositoryService,_super),RepositoryService.$inject=["$q","$tgModel","$tgStorage","$tgHttp","$tgUrls"],RepositoryService.prototype.resolveUrlForModel=function(model){var idAttrName;return idAttrName=model.getIdAttrName(),""+this.urls.resolve(model.getName())+"/"+model[idAttrName]},RepositoryService.prototype.resolveUrlForAttributeModel=function(model){return this.urls.resolve(model.getName(),model.parent)},RepositoryService.prototype.create=function(name,data,dataTypes,extraParams){var defered,promise,url;return null==dataTypes&&(dataTypes={}),null==extraParams&&(extraParams={}),defered=this.q.defer(),url=this.urls.resolve(name),promise=this.http.post(url,JSON.stringify(data)),promise.success(function(_this){return function(_data){return defered.resolve(_this.model.make_model(name,_data,null,dataTypes))}}(this)),promise.error(function(){return function(data){return defered.reject(data)}}(this)),defered.promise},RepositoryService.prototype.remove=function(model,params){var defered,promise,url;return null==params&&(params={}),defered=this.q.defer(),url=this.resolveUrlForModel(model),promise=this.http["delete"](url,{},params),promise.success(function(){return defered.resolve(model)}),promise.error(function(){return defered.reject(model)}),defered.promise},RepositoryService.prototype.saveAll=function(models,patch){var promises;return null==patch&&(patch=!0),promises=_.map(models,function(_this){return function(x){return _this.save(x,!0)}}(this)),this.q.all(promises)},RepositoryService.prototype.save=function(model,patch){var data,defered,promise,url;return null==patch&&(patch=!0),defered=this.q.defer(),!model.isModified()&&patch?(defered.resolve(model),defered.promise):(url=this.resolveUrlForModel(model),data=JSON.stringify(model.getAttrs(patch)),promise=patch?this.http.patch(url,data):this.http.put(url,data),promise.success(function(){return function(data){return model._isModified=!1,model._attrs=_.extend(model.getAttrs(),data),model._modifiedAttrs={},model.applyCasts(),defered.resolve(model)}}(this)),promise.error(function(data){return defered.reject(data)}),defered.promise)},RepositoryService.prototype.saveAttribute=function(model,attribute,patch){var data,defered,promise,url;return null==patch&&(patch=!0),defered=this.q.defer(),!model.isModified()&&patch?(defered.resolve(model),defered.promise):(url=this.resolveUrlForAttributeModel(model),data={},data[attribute]=model.getAttrs(),promise=patch?this.http.patch(url,data):this.http.put(url,data),promise.success(function(){return function(data){return model._isModified=!1,model._attrs=_.extend(model.getAttrs(),data),model._modifiedAttrs={},model.applyCasts(),defered.resolve(model)}}(this)),promise.error(function(data){return defered.reject(data)}),defered.promise)},RepositoryService.prototype.refresh=function(model){var defered,promise,url;return defered=this.q.defer(),url=this.resolveUrlForModel(model),promise=this.http.get(url),promise.success(function(data){return model._modifiedAttrs={},model._attrs=data,model._isModified=!1,model.applyCasts(),defered.resolve(model)}),promise.error(function(data){return defered.reject(data)}),defered.promise},RepositoryService.prototype.queryMany=function(name,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){return _.map(data.data,function(x){return _this.model.make_model(name,x)})}}(this))},RepositoryService.prototype.queryOneAttribute=function(name,id,attribute,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name,id),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){var model;return model=_this.model.make_model(name,data.data[attribute]),model.parent=id,model}}(this))},RepositoryService.prototype.queryOne=function(name,id,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),id&&(url=""+url+"/"+id),httpOptions={headers:{}},options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(_this){return function(data){return _this.model.make_model(name,data.data)}}(this))},RepositoryService.prototype.queryOneRaw=function(name,id,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),id&&(url=""+url+"/"+id),httpOptions=_.merge({headers:{}},options),options.enablePagination||(httpOptions.headers["x-disable-pagination"]="1"),this.http.get(url,params,httpOptions).then(function(){return function(data){return data.data}}(this))},RepositoryService.prototype.queryPaginated=function(name,params,options){var httpOptions,url;return null==options&&(options={}),url=this.urls.resolve(name),httpOptions=_.merge({headers:{}},options),this.http.get(url,params,httpOptions).then(function(_this){return function(data){var headers,result;return headers=data.headers(),result={},result.models=_.map(data.data,function(x){return _this.model.make_model(name,x)}),result.count=parseInt(headers["x-pagination-count"],10),result.current=parseInt(headers["x-pagination-current"]||1,10),result.paginatedBy=parseInt(headers["x-paginated-by"],10),result}}(this))},RepositoryService.prototype.resolve=function(options){var cache,params;return params={},null!=options.pslug&&(params.project=options.pslug),null!=options.usref&&(params.us=options.usref),null!=options.taskref&&(params.task=options.taskref),null!=options.issueref&&(params.issue=options.issueref),null!=options.sslug&&(params.milestone=options.sslug),null!=options.wikipage&&(params.wikipage=options.wikipage),cache=!(options.wikipage||options.sslug),this.queryOneRaw("resolver",null,params,{cache:cache})},RepositoryService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgRepo",RepositoryService)}.call(this),function(){var StorageService,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,StorageService=function(_super){function StorageService(){StorageService.__super__.constructor.call(this)}return __extends(StorageService,_super),StorageService.$inject=["$rootScope"],StorageService.prototype.get=function(key,_default){var serializedValue;return serializedValue=localStorage.getItem(key),null===serializedValue?_default||null:JSON.parse(serializedValue)},StorageService.prototype.set=function(key,val){return _.isObject(key)?_.each(key,function(_this){return function(val,key){return _this.set(key,val)}}(this)):localStorage.setItem(key,JSON.stringify(val))},StorageService.prototype.contains=function(key){var value;return value=this.get(key),null!==value},StorageService.prototype.remove=function(key){return localStorage.removeItem(key)},StorageService.prototype.clear=function(){return localStorage.clear()},StorageService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgStorage",StorageService)}.call(this),function(){var UrlsService,format,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};format=function(fmt,obj){return obj=_.clone(obj),fmt.replace(/%s/g,function(){return String(obj.shift())})},taiga=this.taiga,UrlsService=function(_super){function UrlsService(config){this.config=config,this.urls={},this.mainUrl=config.get("api")}return __extends(UrlsService,_super),UrlsService.$inject=["$tgConfig"],UrlsService.prototype.update=function(urls){return this.urls=_.merge(this.urls,urls)},UrlsService.prototype.resolve=function(){var args,name,url;if(args=_.toArray(arguments),0===args.length)throw Error("wrong arguments to setUrls");return name=args.slice(0,1)[0],url=format(this.urls[name],args.slice(1)),format("%s/%s",[_.str.rtrim(this.mainUrl,"/"),_.str.ltrim(url,"/")])},UrlsService}(taiga.Service),module=angular.module("taigaBase"),module.service("$tgUrls",UrlsService)}.call(this),function(){var module,resourceProvider,sizeFormat,taiga;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,resourceProvider=function($rootScope,$config,$urls,$model,$repo,$auth,$q){var service;return service={},service.list=function(urlName,objectId,projectId){var params;return params={object_id:objectId,project:projectId},$repo.queryMany(urlName,params)},service.create=function(urlName,projectId,objectId,file){var data,defered,maxFileSize,response,uploadComplete,uploadFailed,uploadProgress,xhr;return defered=$q.defer(),void 0===file?(defered.reject(null),defered.promise):(maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&file.size>maxFileSize?(response={status:413,data:{_error_message:"'"+file.name+"' ("+sizeFormat(file.size)+") is too heavy for our oompa loompas, try it with a smaller than ("+sizeFormat(maxFileSize)+")"}},defered.reject(response),defered.promise):(uploadProgress=function(){return function(evt){return $rootScope.$apply(function(){return file.status="in-progress",file.size=sizeFormat(evt.total),file.progressMessage="upload "+sizeFormat(evt.loaded)+" of "+sizeFormat(evt.total),file.progressPercent=""+Math.round(evt.loaded/evt.total*100)+"%"})}}(this),uploadComplete=function(){return function(evt){return $rootScope.$apply(function(){var data,model;file.status="done";try{data=JSON.parse(evt.target.responseText)}catch(_error){data={}}return model=$model.make_model(urlName,data),defered.resolve(model)})}}(this),uploadFailed=function(){return function(){return $rootScope.$apply(function(){return file.status="error",defered.reject("fail")})}}(this),data=new FormData,data.append("project",projectId),data.append("object_id",objectId),data.append("attached_file",file),xhr=new XMLHttpRequest,xhr.upload.addEventListener("progress",uploadProgress,!1),xhr.addEventListener("load",uploadComplete,!1),xhr.addEventListener("error",uploadFailed,!1),xhr.open("POST",$urls.resolve(urlName)),xhr.setRequestHeader("Authorization","Bearer "+$auth.getToken()),xhr.setRequestHeader("Accept","application/json"),xhr.send(data),defered.promise))},function(instance){return instance.attachments=service}},module=angular.module("taigaResources"),module.factory("$tgAttachmentsResourcesProvider",["$rootScope","$tgConfig","$tgUrls","$tgModel","$tgRepo","$tgAuth","$q",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$http,$urls){var service;return service={},service.get=function(type,objectId){return $repo.queryOneRaw("history/"+type,objectId)},service.deleteComment=function(type,objectId,activityId){var params,url;return url=$urls.resolve("history/"+type),url=""+url+"/"+objectId+"/delete_comment",params={id:activityId},$http.post(url,null,params).then(function(){return function(data){return data.data}}(this))},service.undeleteComment=function(type,objectId,activityId){var params,url;return url=$urls.resolve("history/"+type),url=""+url+"/"+objectId+"/undelete_comment",params={id:activityId},$http.post(url,null,params).then(function(){return function(data){return data.data}}(this))},function(instance){return instance.history=service}},module=angular.module("taigaResources"),module.factory("$tgHistoryResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(token){return $repo.queryOne("invitations",token)},function(instance){return instance.invitations=service}},module=angular.module("taigaResources"),module.factory("$tgInvitationsResourcesProvider",["$tgRepo",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage,$q){var filtersHashSuffix,hashSuffix,myFiltersHashSuffix,service;return service={},hashSuffix="issues-queryparams",filtersHashSuffix="issues-filters",myFiltersHashSuffix="issues-my-filters",service.get=function(projectId,issueId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("issues",issueId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("issues","by_ref?project="+projectId+"&ref="+ref)},service.list=function(projectId,filters,options){var params;return params={project:projectId},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryPaginated("issues",params,options)},service.bulkCreate=function(projectId,data){var params,url;return url=$urls.resolve("bulk-create-issues"),params={project_id:projectId,bulk_issues:data},$http.post(url,params)},service.stats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/issues_stats")},service.filtersData=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/issue_filters_data")},service.listValues=function(projectId,type){var params;return params={project:projectId},service.storeQueryParams(projectId,params),$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeFilters=function(projectSlug,params){var hash,ns;return ns=""+projectSlug+":"+filtersHashSuffix,hash=generateHash([projectSlug,ns]),$storage.set(hash,params)},service.getFilters=function(projectSlug){var hash,ns;return ns=""+projectSlug+":"+filtersHashSuffix,hash=generateHash([projectSlug,ns]),$storage.get(hash)||{}},service.storeMyFilters=function(projectId,myFilters){var deferred,hash,ns,promise,url;return deferred=$q.defer(),url=$urls.resolve("user-storage"),ns=""+projectId+":"+myFiltersHashSuffix,hash=generateHash([projectId,ns]),_.isEmpty(myFilters)?(promise=$http["delete"](""+url+"/"+hash,{key:hash,value:myFilters}),promise.then(function(){return deferred.resolve()}),promise.then(null,function(){return deferred.reject()})):(promise=$http.put(""+url+"/"+hash,{key:hash,value:myFilters}),promise.then(function(){return deferred.resolve()}),promise.then(null,function(){var innerPromise;return innerPromise=$http.post(""+url,{key:hash,value:myFilters}),innerPromise.then(function(){return deferred.resolve()}),innerPromise.then(null,function(){return deferred.reject()})})),deferred.promise},service.getMyFilters=function(projectId){var deferred,hash,ns,promise,url;return deferred=$q.defer(),url=$urls.resolve("user-storage"),ns=""+projectId+":"+myFiltersHashSuffix,hash=generateHash([projectId,ns]),promise=$http.get(""+url+"/"+hash),promise.then(function(data){return deferred.resolve(data.data.value)}),promise.then(null,function(){return deferred.resolve({})}),deferred.promise},function(instance){return instance.issues=service}},module=angular.module("taigaResources"),module.factory("$tgIssuesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage","$q",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($storage){var hashSuffixStatusColumnModes,hashSuffixStatusViewModes,service;return service={},hashSuffixStatusViewModes="kanban-statusviewmodels",hashSuffixStatusColumnModes="kanban-statuscolumnmodels",service.storeStatusViewModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusViewModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusViewModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusViewModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeStatusColumnModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusColumnModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},function(instance){return instance.kanban=service}},module=angular.module("taigaResources"),module.factory("$tgKanbanResourcesProvider",["$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$urls,$http){var service;return service={},service.render=function(projectId,content){var params,url;return(null==content||""===content)&&(content=" "),params={project_id:projectId,content:content},url=$urls.resolve("wiki"),$http.post(""+url+"/render",params).then(function(){return function(data){return data.data}}(this))},function(instance){return instance.mdrender=service}},module=angular.module("taigaResources"),module.factory("$tgMdRenderResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$http,$urls){var service;return service={},service.get=function(id){return $repo.queryOne("memberships",id)},service.list=function(projectId,filters,enablePagination){var options,params;return null==enablePagination&&(enablePagination=!0),params={project:projectId},params=_.extend({},params,filters||{}),enablePagination?$repo.queryPaginated("memberships",params):$repo.queryMany("memberships",params,options={enablePagination:enablePagination})},service.listByUser=function(userId,filters){var params;return params={user:userId},params=_.extend({},params,filters||{}),$repo.queryPaginated("memberships",params)},service.resendInvitation=function(id){var url;return url=$urls.resolve("memberships"),$http.post(""+url+"/"+id+"/resend_invitation",{})},service.bulkCreateMemberships=function(projectId,data,invitation_extra_text){var params,url;return url=$urls.resolve("bulk-create-memberships"),params={project_id:projectId,bulk_memberships:data,invitation_extra_text:invitation_extra_text},$http.post(url,params)},function(instance){return instance.memberships=service}},module=angular.module("taigaResources"),module.factory("$tgMembershipsResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider;resourceProvider=function($repo){var service;return service={},service.list=function(projectId,module){return $repo.queryOneAttribute("project-modules",projectId,module)},function(instance){return instance.modules=service}},module=angular.module("taigaResources"),module.factory("$tgModulesResourcesProvider",["$tgRepo",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(id){return $repo.queryOne("notify-policies",id)},service.list=function(filters){var params;return params=_.extend({},params,filters||{}),$repo.queryMany("notify-policies",params)},function(instance){return instance.notifyPolicies=service +}},module=angular.module("taigaResources"),module.factory("$tgNotifyPoliciesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,sizeFormat,taiga;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,resourceProvider=function($config,$repo,$http,$urls,$auth,$q){var service;return service={},service.get=function(projectId){return $repo.queryOne("projects",projectId)},service.getBySlug=function(projectSlug){return $repo.queryOne("projects","by_slug?slug="+projectSlug)},service.list=function(){return $repo.queryMany("projects")},service.templates=function(){return $repo.queryMany("project-templates")},service.usersList=function(projectId){var params;return params={project:projectId},$repo.queryMany("users",params)},service.rolesList=function(projectId){var params;return params={project:projectId},$repo.queryMany("roles",params)},service.stats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/stats")},service.leave=function(projectId){var url;return url=""+$urls.resolve("projects")+"/"+projectId+"/leave",$http.post(url)},service.memberStats=function(projectId){return $repo.queryOneRaw("projects",""+projectId+"/member_stats")},service.tagsColors=function(projectId){return $repo.queryOne("projects",""+projectId+"/tags_colors")},service["export"]=function(projectId){var url;return url=""+$urls.resolve("exporter")+"/"+projectId,$http.get(url)},service["import"]=function(file,statusUpdater){var complete,data,defered,failed,maxFileSize,response,uploadComplete,uploadFailed,uploadProgress,xhr;return defered=$q.defer(),maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&file.size>maxFileSize?(response={status:413,data:{_error_message:"'"+file.name+"' ("+sizeFormat(file.size)+") is too heavy for our oompa loompas, try it with a smaller than ("+sizeFormat(maxFileSize)+")"}},defered.reject(response),defered.promise):(uploadProgress=function(){return function(evt){var message,percent;return percent=Math.round(evt.loaded/evt.total*100),message="Uloaded "+sizeFormat(evt.loaded)+" of "+sizeFormat(evt.total),statusUpdater("in-progress",null,message,percent)}}(this),uploadComplete=function(){return function(){return statusUpdater("done","Importing Project","This process can take a while, please keep the window open.")}}(this),uploadFailed=function(){return function(){return statusUpdater("error")}}(this),complete=function(){return function(evt){var _ref;response={};try{response.data=JSON.parse(evt.target.responseText)}catch(_error){response.data={}}return response.status=evt.target.status,(201===(_ref=response.status)||202===_ref)&&defered.resolve(response),defered.reject(response)}}(this),failed=function(){return function(){return defered.reject("fail")}}(this),data=new FormData,data.append("dump",file),xhr=new XMLHttpRequest,xhr.upload.addEventListener("progress",uploadProgress,!1),xhr.upload.addEventListener("load",uploadComplete,!1),xhr.upload.addEventListener("error",uploadFailed,!1),xhr.upload.addEventListener("abort",uploadFailed,!1),xhr.addEventListener("load",complete,!1),xhr.addEventListener("error",failed,!1),xhr.open("POST",$urls.resolve("importer")),xhr.setRequestHeader("Authorization","Bearer "+$auth.getToken()),xhr.setRequestHeader("Accept","application/json"),xhr.send(data),defered.promise)},function(instance){return instance.projects=service}},module=angular.module("taigaResources"),module.factory("$tgProjectsResourcesProvider",["$tgConfig","$tgRepo","$tgHttp","$tgUrls","$tgAuth","$q",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(id){return $repo.queryOne("roles",id)},service.list=function(projectId){return $repo.queryMany("roles",{project:projectId})},function(instance){return instance.roles=service}},module=angular.module("taigaResources"),module.factory("$tgRolesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo,$urls,$http){var service;return service={},service["do"]=function(projectId,term){var params,url;return url=$urls.resolve("search"),params={project:projectId,text:term,get_all:!1},$http.get(url,params).then(function(data){return data.data})},function(instance){return instance.search=service}},module=angular.module("taigaResources"),module.factory("$tgSearchResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$model,$storage){var hashSuffixUserstories,service;return service={},hashSuffixUserstories="userstories-queryparams",service.get=function(projectId,sprintId){return $repo.queryOne("milestones",sprintId).then(function(sprint){var uses;return service.storeUserstoriesQueryParams(projectId,{milestone:sprintId}),uses=sprint.user_stories,uses=_.map(uses,function(u){return $model.make_model("userstories",u)}),sprint._attrs.user_stories=uses,sprint})},service.stats=function(projectId,sprintId){return $repo.queryOneRaw("milestones",""+sprintId+"/stats")},service.list=function(projectId,filters){var params;return params={project:projectId},params=_.extend({},params,filters||{}),$repo.queryMany("milestones",params).then(function(){return function(milestones){var m,uses,_i,_len;for(_i=0,_len=milestones.length;_len>_i;_i++)m=milestones[_i],uses=m.user_stories,uses=_.map(uses,function(u){return $model.make_model("userstories",u)}),m._attrs.user_stories=uses;return milestones}}(this))},service.storeUserstoriesQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixUserstories,hash=generateHash([projectId,ns]),$storage.set(hash,params)},function(instance){return instance.sprints=service}},module=angular.module("taigaResources"),module.factory("$tgSprintsResourcesProvider",["$tgRepo","$tgModel","$tgStorage",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage){var hashSuffix,hashSuffixStatusColumnModes,hashSuffixUsRowModes,service;return service={},hashSuffix="tasks-queryparams",hashSuffixStatusColumnModes="tasks-statuscolumnmodels",hashSuffixUsRowModes="tasks-usrowmodels",service.get=function(projectId,taskId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("tasks",taskId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("tasks","by_ref?project="+projectId+"&ref="+ref)},service.list=function(projectId,sprintId,userStoryId){var params;return null==sprintId&&(sprintId=null),null==userStoryId&&(userStoryId=null),params={project:projectId},sprintId&&(params.milestone=sprintId),userStoryId&&(params.user_story=userStoryId),service.storeQueryParams(projectId,params),$repo.queryMany("tasks",params)},service.bulkCreate=function(projectId,sprintId,usId,data){var params,url;return url=$urls.resolve("bulk-create-tasks"),params={project_id:projectId,sprint_id:sprintId,us_id:usId,bulk_tasks:data},$http.post(url,params).then(function(result){return result.data})},service.bulkUpdateTaskTaskboardOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-task-taskboard-order"),params={project_id:projectId,bulk_tasks:data},$http.post(url,params)},service.listValues=function(projectId,type){var params;return params={project:projectId},$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeStatusColumnModes=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getStatusColumnModes=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffixStatusColumnModes,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeUsRowModes=function(projectId,sprintId,params){var hash,ns;return ns=""+projectId+":"+hashSuffixUsRowModes,hash=generateHash([projectId,sprintId,ns]),$storage.set(hash,params)},service.getUsRowModes=function(projectId,sprintId){var hash,ns;return ns=""+projectId+":"+hashSuffixUsRowModes,hash=generateHash([projectId,sprintId,ns]),$storage.get(hash)||{}},function(instance){return instance.tasks=service}},module=angular.module("taigaResources"),module.factory("$tgTasksResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider,sizeFormat,taiga;taiga=this.taiga,sizeFormat=this.taiga.sizeFormat,resourceProvider=function($config,$repo,$http,$urls,$q){var service;return service={},service.changeAvatar=function(file){var data,defered,maxFileSize,options,response,url;return maxFileSize=$config.get("maxUploadFileSize",null),maxFileSize&&file.size>maxFileSize?(response={status:413,data:{_error_message:"'"+file.name+"' ("+sizeFormat(file.size)+") is too heavy for our oompa loompas, try it with a smaller than ("+sizeFormat(maxFileSize)+")"}},defered=$q.defer(),defered.reject(response),defered.promise):(data=new FormData,data.append("avatar",file),options={transformRequest:angular.identity,headers:{"Content-Type":void 0}},url=""+$urls.resolve("users")+"/change_avatar",$http.post(url,data,{},options))},service.removeAvatar=function(){var url;return url=""+$urls.resolve("users")+"/remove_avatar",$http.post(url)},service.changePassword=function(currentPassword,newPassword){var data,url;return url=""+$urls.resolve("users")+"/change_password",data={current_password:currentPassword,password:newPassword},$http.post(url,data)},function(instance){return instance.userSettings=service}},module=angular.module("taigaResources"),module.factory("$tgUserSettingsResourcesProvider",["$tgConfig","$tgRepo","$tgHttp","$tgUrls","$q",resourceProvider])}.call(this),function(){var generateHash,module,resourceProvider,taiga;taiga=this.taiga,generateHash=taiga.generateHash,resourceProvider=function($repo,$http,$urls,$storage){var hashSuffix,service;return service={},hashSuffix="userstories-queryparams",service.get=function(projectId,usId){var params;return params=service.getQueryParams(projectId),params.project=projectId,$repo.queryOne("userstories",usId,params)},service.getByRef=function(projectId,ref){return $repo.queryOne("userstories","by_ref?project="+projectId+"&ref="+ref)},service.listUnassigned=function(projectId,filters){var params;return params={project:projectId,milestone:"null"},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryMany("userstories",params)},service.listAll=function(projectId,filters){var params;return params={project:projectId},params=_.extend({},params,filters||{}),service.storeQueryParams(projectId,params),$repo.queryMany("userstories",params)},service.bulkCreate=function(projectId,status,bulk){var data,url;return data={project_id:projectId,status_id:status,bulk_stories:bulk},url=$urls.resolve("bulk-create-us"),$http.post(url,data)},service.bulkUpdateBacklogOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-backlog-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.bulkUpdateSprintOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-sprint-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.bulkUpdateKanbanOrder=function(projectId,data){var params,url;return url=$urls.resolve("bulk-update-us-kanban-order"),params={project_id:projectId,bulk_stories:data},$http.post(url,params)},service.listValues=function(projectId,type){var params;return params={project:projectId},service.storeQueryParams(projectId,params),$repo.queryMany(type,params)},service.storeQueryParams=function(projectId,params){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.set(hash,params)},service.getQueryParams=function(projectId){var hash,ns;return ns=""+projectId+":"+hashSuffix,hash=generateHash([projectId,ns]),$storage.get(hash)||{}},service.storeShowTags=function(projectId,showTags){var hash;return hash=generateHash([projectId,"showTags"]),$storage.set(hash,showTags)},service.getShowTags=function(projectId){var hash;return hash=generateHash([projectId,"showTags"]),$storage.get(hash)||null},function(instance){return instance.userstories=service}},module=angular.module("taigaResources"),module.factory("$tgUserstoriesResourcesProvider",["$tgRepo","$tgHttp","$tgUrls","$tgStorage",resourceProvider])}.call(this),function(){var module,resourceProvider;resourceProvider=function($repo,$urls,$http){var service;return service={},service.list=function(webhookId){var params;return params={webhook:webhookId},$repo.queryMany("webhooklogs",params)},service.resend=function(webhooklogId){var url;return url=$urls.resolve("webhooklogs-resend",webhooklogId),$http.post(url)},function(instance){return instance.webhooklogs=service}},module=angular.module("taigaResources"),module.factory("$tgWebhookLogsResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var module,resourceProvider;resourceProvider=function($repo,$urls,$http){var service;return service={},service.list=function(projectId){var params;return params={project:projectId},$repo.queryMany("webhooks",params)},service.test=function(webhookId){var url;return url=$urls.resolve("webhooks-test",webhookId),$http.post(url)},function(instance){return instance.webhooks=service}},module=angular.module("taigaResources"),module.factory("$tgWebhooksResourcesProvider",["$tgRepo","$tgUrls","$tgHttp",resourceProvider])}.call(this),function(){var module,resourceProvider,taiga;taiga=this.taiga,resourceProvider=function($repo){var service;return service={},service.get=function(wikiId){return $repo.queryOne("wiki",wikiId)},service.getBySlug=function(projectId,slug){return $repo.queryOne("wiki","by_slug?project="+projectId+"&slug="+slug)},service.listLinks=function(projectId){return $repo.queryMany("wiki-links",{project:projectId})},function(instance){return instance.wiki=service}},module=angular.module("taigaResources"),module.factory("$tgWikiResourcesProvider",["$tgRepo","$tgHttp","$tgUrls",resourceProvider])}.call(this),function(){var UserChangePasswordController,UserChangePasswordDirective,debounce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,debounce=this.taiga.debounce,module=angular.module("taigaUserSettings"),UserChangePasswordController=function(_super){function UserChangePasswordController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,auth){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="Change Password",this.scope.project={},this.scope.user=this.auth.getUser(),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserChangePasswordController,_super),UserChangePasswordController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserChangePasswordController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserChangePasswordController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},UserChangePasswordController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserChangePasswordController",UserChangePasswordController),UserChangePasswordDirective=function($rs,$confirm,$loading){var link;return link=function($scope,$el){var submit,submitButton;return submit=debounce(2e3,function(){return function(event){var promise;return event.preventDefault(),$scope.newPassword1!==$scope.newPassword2?void $confirm.notify("error","The passwords dosn't match"):($loading.start(submitButton),promise=$rs.userSettings.changePassword($scope.currentPassword,$scope.newPassword1),promise.then(function(){return $loading.finish(submitButton),$confirm.notify("success")}),promise.then(null,function(response){return $loading.finish(submitButton),$confirm.notify("error",response.data._error_message)}))}}(this)),submitButton=$el.find(".submit-button"),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserChangePassword",["$tgResources","$tgConfirm","$tgLoading",UserChangePasswordDirective])}.call(this),function(){var DeleteUserDirective,bindOnce,debounce,module,taiga;taiga=this.taiga,bindOnce=this.taiga.bindOnce,debounce=this.taiga.debounce,module=angular.module("taigaUserSettings"),DeleteUserDirective=function($repo,$rootscope,$auth,$location,$navUrls,lightboxService){var link;return link=function($scope,$el){var submit;return $scope.$on("deletelightbox:new",function(){return lightboxService.open($el)}),$scope.$on("$destroy",function(){return $el.off()}),submit=function(){var promise;return promise=$repo.remove($scope.user),promise.then(function(){return lightboxService.close($el),$auth.logout(),$location.path($navUrls.resolve("login"))}),promise.then(null,function(){return console.log("FAIL")})},$el.on("click",".button-red",function(event){return event.preventDefault(),lightboxService.close($el)}),$el.on("click",".button-green",debounce(2e3,function(event){return event.preventDefault(),submit()}))},{link:link,templateUrl:"user/lightbox/lightbox-delete-account.html"}},module.directive("tgLbDeleteUser",["$tgRepo","$rootScope","$tgAuth","$tgLocation","$tgNavUrls","lightboxService",DeleteUserDirective])}.call(this),function(){var TaigaAvatarModelDirective,UserAvatarDirective,UserProfileDirective,UserSettingsController,debounce,mixOf,module,sizeFormat,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,sizeFormat=this.taiga.sizeFormat,module=angular.module("taigaUserSettings"),debounce=this.taiga.debounce,UserSettingsController=function(_super){function UserSettingsController(scope,rootscope,config,repo,confirm,rs,params,q,location,navUrls,auth){var maxFileSize,promise;this.scope=scope,this.rootscope=rootscope,this.config=config,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="User Profile",this.scope.project={},this.scope.user=this.auth.getUser(),maxFileSize=this.config.get("maxUploadFileSize",null),maxFileSize&&(this.scope.maxFileSizeMsg="[Max, size: "+sizeFormat(maxFileSize)),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserSettingsController,_super),UserSettingsController.$inject=["$scope","$rootScope","$tgConfig","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserSettingsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserSettingsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this))},UserSettingsController.prototype.openDeleteLightbox=function(){return this.rootscope.$broadcast("deletelightbox:new",this.scope.user)},UserSettingsController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserSettingsController",UserSettingsController),UserProfileDirective=function($confirm,$auth,$repo){var link;return link=function($scope,$el){var submit;return submit=debounce(2e3,function(){return function(event){var changeEmail,form,onError,onSuccess;return event.preventDefault(),form=$el.find("form").checksley(),form.validate()?(changeEmail=$scope.user.isAttributeModified("email"),onSuccess=function(){return $auth.setUser($scope.user),changeEmail?$confirm.success("Check your inbox!
    We have sent a mail to your account
    with the instructions to set your new address"):$confirm.notify("success")},onError=function(data){return form.setErrors(data),$confirm.notify("error",data._error_message)},$repo.save($scope.user).then(onSuccess,onError)):void 0}}(this)),$el.on("submit","form",submit),$el.on("click",".submit-button",submit),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserProfile",["$tgConfirm","$tgAuth","$tgRepo",UserProfileDirective]),UserAvatarDirective=function($auth,$model,$rs,$confirm){var link;return link=function($scope,$el){var onError,onSuccess,showSizeInfo;return showSizeInfo=function(){return $el.find(".size-info").removeClass("hidden")},onSuccess=function(response){var user;return user=$model.make_model("users",response.data),$auth.setUser(user),$scope.user=user,$el.find(".overlay").hide(),$confirm.notify("success")},onError=function(response){return 413===response.status&&showSizeInfo(),$el.find(".overlay").hide(),$confirm.notify("error",response.data._error_message)},$el.on("click",".button.change",function(){return $el.find("#avatar-field").click()}),$el.on("change","#avatar-field",function(){return $scope.avatarAttachment?($el.find(".overlay").css("display","flex"),$rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess,onError)):void 0}),$el.on("click","a.use-gravatar",function(){return $el.find(".overlay").show(),$rs.userSettings.removeAvatar().then(onSuccess,onError)}),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserAvatar",["$tgAuth","$tgModel","$tgResources","$tgConfirm",UserAvatarDirective]),TaigaAvatarModelDirective=function($parse){var link;return link=function($scope,$el,$attrs){var model,modelSetter;return model=$parse($attrs.tgAvatarModel),modelSetter=model.assign,$el.bind("change",function(){return $scope.$apply(function(){return modelSetter($scope,$el[0].files[0])})})},{link:link}},module.directive("tgAvatarModel",["$parse",TaigaAvatarModelDirective])}.call(this),function(){var UserSettingsNavigationDirective,module;UserSettingsNavigationDirective=function(){var link;return link=function($scope,$el,$attrs){var section;return section=$attrs.tgUserSettingsNavigation,$el.find(".active").removeClass("active"),$el.find("#usersettingsmenu-"+section+" a").addClass("active"),$scope.$on("$destroy",function(){return $el.off()})},{link:link}},module=angular.module("taigaUserSettings"),module.directive("tgUserSettingsNavigation",UserSettingsNavigationDirective)}.call(this),function(){var UserNotificationsController,UserNotificationsDirective,UserNotificationsListDirective,bindOnce,mixOf,module,taiga,__hasProp={}.hasOwnProperty,__extends=function(child,parent){function ctor(){this.constructor=child}for(var key in parent)__hasProp.call(parent,key)&&(child[key]=parent[key]);return ctor.prototype=parent.prototype,child.prototype=new ctor,child.__super__=parent.prototype,child};taiga=this.taiga,mixOf=this.taiga.mixOf,bindOnce=this.taiga.bindOnce,module=angular.module("taigaUserSettings"),UserNotificationsController=function(_super){function UserNotificationsController(scope,rootscope,repo,confirm,rs,params,q,location,navUrls,auth){var promise;this.scope=scope,this.rootscope=rootscope,this.repo=repo,this.confirm=confirm,this.rs=rs,this.params=params,this.q=q,this.location=location,this.navUrls=navUrls,this.auth=auth,this.scope.sectionName="Email Notifications",this.scope.project={},this.scope.user=this.auth.getUser(),promise=this.loadInitialData(),promise.then(null,this.onInitialDataError.bind(this))}return __extends(UserNotificationsController,_super),UserNotificationsController.$inject=["$scope","$rootScope","$tgRepo","$tgConfirm","$tgResources","$routeParams","$q","$tgLocation","$tgNavUrls","$tgAuth"],UserNotificationsController.prototype.loadProject=function(){return this.rs.projects.get(this.scope.projectId).then(function(_this){return function(project){return _this.scope.project=project,_this.scope.$emit("project:loaded",project),project}}(this))},UserNotificationsController.prototype.loadNotifyPolicies=function(){return this.rs.notifyPolicies.list().then(function(_this){return function(notifyPolicies){return _this.scope.notifyPolicies=notifyPolicies,notifyPolicies}}(this))},UserNotificationsController.prototype.loadInitialData=function(){var promise;return promise=this.repo.resolve({pslug:this.params.pslug}).then(function(_this){return function(data){return _this.scope.projectId=data.project,data}}(this)),promise.then(function(_this){return function(){return _this.loadProject()}}(this)).then(function(_this){return function(){return _this.loadNotifyPolicies()}}(this))},UserNotificationsController}(mixOf(taiga.Controller,taiga.PageMixin)),module.controller("UserNotificationsController",UserNotificationsController),UserNotificationsDirective=function(){var link;return link=function($scope,$el){return $scope.$on("$destroy",function(){return $el.off()})},{link:link}},module.directive("tgUserNotifications",UserNotificationsDirective),UserNotificationsListDirective=function($repo,$confirm){var link,template;return template=_.template('<% _.each(notifyPolicies, function (notifyPolicy, index) { %>\n
    \n
    <%- notifyPolicy.project_name %>
    \n
    \n
    \n checked="checked"<% } %>/>\n \n
    \n
    \n
    \n
    \n checked="checked"<% } %> />\n \n
    \n
    \n
    \n
    \n checked="checked"<% } %> />\n \n
    \n
    \n
    \n<% }) %>'),link=function($scope,$el,$attrs){var render;return render=function(){return $el.off(),$el.html(template({notifyPolicies:$scope.notifyPolicies})),$el.on("change","input[type=radio]",function(event){var onError,onSuccess,policy,policyIndex,prev_level,target;return target=angular.element(event.currentTarget),policyIndex=target.parents(".policy-table-row").data("index"),policy=$scope.notifyPolicies[policyIndex],prev_level=policy.notify_level,policy.notify_level=parseInt(target.val(),10),onSuccess=function(){return $confirm.notify("success")},onError=function(){return $confirm.notify("error"),target.parents(".policy-table-row").find("input[value="+prev_level+"]").prop("checked",!0)},$repo.save(policy).then(onSuccess,onError)})},$scope.$on("$destroy",function(){return $el.off()}),bindOnce($scope,$attrs.ngModel,render)},{link:link}},module.directive("tgUserNotificationsList",["$tgRepo","$tgConfirm",UserNotificationsListDirective])}.call(this),function(){var AUTH_URL,GithubLoginButtonDirective,module,taiga;taiga=this.taiga,module=angular.module("taigaIntegrations"),AUTH_URL="https://github.com/login/oauth/authorize",GithubLoginButtonDirective=function($window,$params,$location,$config,$events,$confirm,$auth,$navUrls,$loader){var link,template;return template='
    \n \n Login with Github\n',link=function($scope,$el){var clientId,loginOnError,loginOnSuccess,loginWithGitHubAccount,renderGitHubButton;return(clientId=$config.get("gitHubClientId",null))?(renderGitHubButton=function(){return clientId?$el.html(template):void 0},loginOnSuccess=function(){var nextUrl;return nextUrl=$params.next&&$params.next!==$navUrls.resolve("login")?$params.next:$navUrls.resolve("home"),$events.setupConnection(),$location.search("next",null),$location.search("token",null),$location.search("state",null),$location.search("code",null),$location.path(nextUrl)},loginOnError=function(response){return $location.search("state",null),$location.search("code",null),$loader.pageLoaded(),response.data.error_message?$confirm.notify("light-error",response.data.error_message):$confirm.notify("light-error","Our Oompa Loompas have not been able to get you credentials from GitHub.")},loginWithGitHubAccount=function(){var code,data,token,type;return type=$params.state,code=$params.code,token=$params.token,"github"===type&&code?($loader.start(),data={code:code,token:token},$auth.login(data,type).then(loginOnSuccess,loginOnError)):void 0},renderGitHubButton(),loginWithGitHubAccount(),$el.on("click",".button-github",function(){var redirectToUri,url;return redirectToUri=$location.absUrl(),url=""+AUTH_URL+"?client_id="+clientId+"&redirect_uri="+redirectToUri+"&state=github&scope=user:email",$window.location.href=url}),$scope.$on("$destroy",function(){return $el.off()})):void 0},{link:link,restrict:"EA",template:""}},module.directive("tgGithubLoginButton",["$window","$routeParams","$tgLocation","$tgConfig","$tgEvents","$tgConfirm","$tgAuth","$tgNavUrls","tgLoader",GithubLoginButtonDirective])}.call(this),function(){var configure,module,taiga;taiga=this.taiga,module=angular.module("taigaPlugins",["ngRoute"]),configure=function($routeProvider){return $routeProvider.when("/humans.html",{templateUrl:"/plugins/humanshtml/templates/humans.html"})},module.config(["$routeProvider",configure])}.call(this),function(){var TermsNoticeDirective,module,taiga,template;taiga=this.taiga,module=angular.module("taigaPlugins",["ngRoute"]),template=_.template('

    \n By clicking "Sign up", you agree to our
    \n terms of service\n and\n privacy policy.\n

    '),TermsNoticeDirective=function($config){var privacyPolicyUrl,templateFn,termsOfServiceUrl;return privacyPolicyUrl=$config.get("privacyPolicyUrl"),termsOfServiceUrl=$config.get("termsOfServiceUrl"),templateFn=function(){var ctx; +return privacyPolicyUrl&&termsOfServiceUrl?(ctx={termsUrl:termsOfServiceUrl,privacyUrl:privacyPolicyUrl},template(ctx)):""},{scope:{},restrict:"AE",template:templateFn}},module.directive("tgTermsNotice",["$tgConfig",TermsNoticeDirective])}.call(this),function(){var module;module=angular.module("taigaPlugins",["ngRoute"])}.call(this),angular.module("taigaBase").value("localesEn",{checksley:{defaultMessage:"This value seems to be invalid.","type-email":"This value should be a valid email.","type-url":"This value should be a valid url.","type-urlstrict":"This value should be a valid url.","type-number":"This value should be a valid number.","type-digits":"This value should be digits.","type-dateIso":"This value should be a valid date (YYYY-MM-DD).","type-alphanum":"This value should be alphanumeric.","type-phone":"This value should be a valid phone number.",notnull:"This value should not be null.",notblank:"This value should not be blank.",required:"This value is required.",regexp:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or less.",rangelength:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or less.",rangecheck:"You must select between %s and %s choices.",equalto:"This value should be the same."},common:{subject:"Subject",save:"Save",blocked:"Blocked",cancel:"Cancel",status:"Status","new-bulk":"New bulk insert","one-item-line":"One item per line..."},pagination:{next:"Next",prev:"Previous"},"markdown-editor":{"heading-1":"First Level Heading","heading-2":"Second Level Heading","heading-3":"Third Level Heading",bold:"Bold",italic:"Italic",strike:"Strike","bulleted-list":"Bulleted List","numeric-list":"Numeric List",picture:"Picture",link:"Link",quotes:"Quotes","code-block":"Code Block / Code",preview:"Preview",help:"Help",placeholder:"Your title here...","link-placeholder":"Your text to link here..."},us:{"title-new":"New User Story","team-requirement":"Team Requirement","client-requirement":"Client Requirement"}}); //# sourceMappingURL=app.js.map \ No newline at end of file diff --git a/dist/js/app.js.map b/dist/js/app.js.map index 0027c4f..2e50f21 100644 --- a/dist/js/app.js.map +++ b/dist/js/app.js.map @@ -1 +1 @@ -{"version":3,"sources":["app.js","locales.en.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC/ypBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"app.js","sourcesContent":["\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: app.coffee\n */\n\n(function() {\n var configure, init, module, modules, taiga;\n\n this.taiga = taiga = {};\n\n this.taigaContribPlugins = this.taigaContribPlugins || [];\n\n taiga.generateHash = function(components) {\n if (components == null) {\n components = [];\n }\n components = _.map(components, function(x) {\n return JSON.stringify(x);\n });\n return hex_sha1(components.join(\":\"));\n };\n\n taiga.generateUniqueSessionIdentifier = function() {\n var date, randomNumber;\n date = (new Date()).getTime();\n randomNumber = Math.floor(Math.random() * 0x9000000);\n return taiga.generateHash([date, randomNumber]);\n };\n\n taiga.sessionId = taiga.generateUniqueSessionIdentifier();\n\n configure = function($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider) {\n var authHttpIntercept, defaultHeaders, versionCheckHttpIntercept;\n $routeProvider.when(\"/\", {\n templateUrl: \"/partials/projects.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/\", {\n templateUrl: \"/partials/project.html\"\n });\n $routeProvider.when(\"/project/:pslug/backlog\", {\n templateUrl: \"/partials/backlog.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/taskboard/:sslug\", {\n templateUrl: \"/partials/taskboard.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/search\", {\n templateUrl: \"/partials/search.html\",\n reloadOnSearch: false\n });\n $routeProvider.when(\"/project/:pslug/kanban\", {\n templateUrl: \"/partials/kanban.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/us/:usref\", {\n templateUrl: \"/partials/us-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/task/:taskref\", {\n templateUrl: \"/partials/task-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/wiki\", {\n redirectTo: function(params) {\n return \"/project/\" + params.pslug + \"/wiki/home\";\n }\n });\n $routeProvider.when(\"/project/:pslug/wiki/:slug\", {\n templateUrl: \"/partials/wiki.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/team\", {\n templateUrl: \"/partials/views/team/team.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/issues\", {\n templateUrl: \"/partials/issues.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/issue/:issueref\", {\n templateUrl: \"/partials/issues-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/details\", {\n templateUrl: \"/partials/admin-project-profile.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/default-values\", {\n templateUrl: \"/partials/admin-project-default-values.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/modules\", {\n templateUrl: \"/partials/admin-project-modules.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/us-status\", {\n templateUrl: \"/partials/admin-project-values-us-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/us-points\", {\n templateUrl: \"/partials/admin-project-values-us-points.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/task-status\", {\n templateUrl: \"/partials/admin-project-values-task-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-status\", {\n templateUrl: \"/partials/admin-project-values-issue-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-types\", {\n templateUrl: \"/partials/admin-project-values-issue-types.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-priorities\", {\n templateUrl: \"/partials/admin-project-values-issue-priorities.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-severities\", {\n templateUrl: \"/partials/admin-project-values-issue-severities.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/memberships\", {\n templateUrl: \"/partials/admin-memberships.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/roles\", {\n templateUrl: \"/partials/admin-roles.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/github\", {\n templateUrl: \"/partials/admin-third-parties-github.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/gitlab\", {\n templateUrl: \"/partials/admin-third-parties-gitlab.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/bitbucket\", {\n templateUrl: \"/partials/admin-third-parties-bitbucket.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/contrib/:plugin\", {\n templateUrl: \"/partials/contrib/main.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-profile\", {\n templateUrl: \"/partials/user-profile.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-change-password\", {\n templateUrl: \"/partials/user-change-password.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-avatar\", {\n templateUrl: \"/partials/user-avatar.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/mail-notifications\", {\n templateUrl: \"/partials/mail-notifications.html\"\n });\n $routeProvider.when(\"/change-email/:email_token\", {\n templateUrl: \"/partials/change-email.html\"\n });\n $routeProvider.when(\"/cancel-account/:cancel_token\", {\n templateUrl: \"/partials/cancel-account.html\"\n });\n $routeProvider.when(\"/login\", {\n templateUrl: \"/partials/login.html\"\n });\n $routeProvider.when(\"/register\", {\n templateUrl: \"/partials/register.html\"\n });\n $routeProvider.when(\"/forgot-password\", {\n templateUrl: \"/partials/forgot-password.html\"\n });\n $routeProvider.when(\"/change-password\", {\n templateUrl: \"/partials/change-password-from-recovery.html\"\n });\n $routeProvider.when(\"/change-password/:token\", {\n templateUrl: \"/partials/change-password-from-recovery.html\"\n });\n $routeProvider.when(\"/invitation/:token\", {\n templateUrl: \"/partials/invitation.html\"\n });\n $routeProvider.when(\"/error\", {\n templateUrl: \"/partials/error.html\"\n });\n $routeProvider.when(\"/not-found\", {\n templateUrl: \"/partials/not-found.html\"\n });\n $routeProvider.when(\"/permission-denied\", {\n templateUrl: \"/partials/permission-denied.html\"\n });\n $routeProvider.otherwise({\n redirectTo: '/not-found'\n });\n $locationProvider.html5Mode({\n enabled: true,\n requireBase: false\n });\n defaultHeaders = {\n \"Content-Type\": \"application/json\",\n \"Accept-Language\": \"en\",\n \"X-Session-Id\": taiga.sessionId\n };\n $httpProvider.defaults.headers[\"delete\"] = defaultHeaders;\n $httpProvider.defaults.headers.patch = defaultHeaders;\n $httpProvider.defaults.headers.post = defaultHeaders;\n $httpProvider.defaults.headers.put = defaultHeaders;\n $httpProvider.defaults.headers.get = {\n \"X-Session-Id\": taiga.sessionId\n };\n $tgEventsProvider.setSessionId(taiga.sessionId);\n authHttpIntercept = function($q, $location, $navUrls, $lightboxService) {\n var httpResponseError;\n httpResponseError = function(response) {\n var nextPath;\n if (response.status === 0) {\n $lightboxService.closeAll();\n $location.path($navUrls.resolve(\"error\"));\n $location.replace();\n } else if (response.status === 401) {\n nextPath = $location.path();\n $location.url($navUrls.resolve(\"login\")).search(\"next=\" + nextPath);\n }\n return $q.reject(response);\n };\n return {\n responseError: httpResponseError\n };\n };\n $provide.factory(\"authHttpIntercept\", [\"$q\", \"$location\", \"$tgNavUrls\", \"lightboxService\", authHttpIntercept]);\n $httpProvider.interceptors.push('authHttpIntercept');\n versionCheckHttpIntercept = function($q, $confirm) {\n var httpResponseError, versionErrorMsg;\n versionErrorMsg = \"Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost).\";\n httpResponseError = function(response) {\n if (response.status === 400 && response.data.version) {\n $confirm.notify(\"error\", versionErrorMsg, null, 10000);\n return $q.reject(response);\n }\n return $q.reject(response);\n };\n return {\n responseError: httpResponseError\n };\n };\n $provide.factory(\"versionCheckHttpIntercept\", [\"$q\", \"$tgConfirm\", versionCheckHttpIntercept]);\n $httpProvider.interceptors.push('versionCheckHttpIntercept');\n window.checksley.updateValidators({\n linewidth: function(val, width) {\n var lines, valid;\n lines = taiga.nl2br(val).split(\"
    \");\n valid = _.every(lines, function(line) {\n return line.length < width;\n });\n return valid;\n }\n });\n return window.checksley.updateMessages(\"default\", {\n linewidth: \"The subject must have a maximum size of %s\"\n });\n };\n\n init = function($log, $i18n, $config, $rootscope, $auth, $events, $analytics) {\n $i18n.initialize($config.get(\"defaultLanguage\"));\n $log.debug(\"Initialize application\");\n $rootscope.contribPlugins = this.taigaContribPlugins;\n if ($auth.isAuthenticated()) {\n $events.setupConnection();\n }\n return $analytics.initialize();\n };\n\n modules = [\"taigaBase\", \"taigaCommon\", \"taigaResources\", \"taigaLocales\", \"taigaAuth\", \"taigaEvents\", \"taigaRelatedTasks\", \"taigaBacklog\", \"taigaTaskboard\", \"taigaKanban\", \"taigaIssues\", \"taigaUserStories\", \"taigaTasks\", \"taigaTeam\", \"taigaWiki\", \"taigaSearch\", \"taigaAdmin\", \"taigaNavMenu\", \"taigaProject\", \"taigaUserSettings\", \"taigaFeedback\", \"taigaPlugins\", \"taigaIntegrations\", \"ngRoute\", \"ngAnimate\"].concat(_.map(this.taigaContribPlugins, function(plugin) {\n return plugin.module;\n }));\n\n module = angular.module(\"taiga\", modules);\n\n module.config([\"$routeProvider\", \"$locationProvider\", \"$httpProvider\", \"$provide\", \"$tgEventsProvider\", \"tgLoaderProvider\", configure]);\n\n module.run([\"$log\", \"$tgI18n\", \"$tgConfig\", \"$rootScope\", \"$tgAuth\", \"$tgEvents\", \"$tgAnalytics\", init]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: classes.coffee\n */\n\n(function() {\n var TaigaBase, TaigaController, TaigaService,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };\n\n TaigaBase = (function() {\n function TaigaBase() {}\n\n return TaigaBase;\n\n })();\n\n TaigaService = (function(_super) {\n __extends(TaigaService, _super);\n\n function TaigaService() {\n return TaigaService.__super__.constructor.apply(this, arguments);\n }\n\n return TaigaService;\n\n })(TaigaBase);\n\n TaigaController = (function(_super) {\n __extends(TaigaController, _super);\n\n function TaigaController() {\n this.onInitialDataError = __bind(this.onInitialDataError, this);\n return TaigaController.__super__.constructor.apply(this, arguments);\n }\n\n TaigaController.prototype.onInitialDataError = function(xhr) {\n if (xhr) {\n if (xhr.status === 404) {\n this.location.path(this.navUrls.resolve(\"not-found\"));\n this.location.replace();\n } else if (xhr.status === 403) {\n this.location.path(this.navUrls.resolve(\"permission-denied\"));\n this.location.replace();\n }\n }\n return this.q.reject(xhr);\n };\n\n return TaigaController;\n\n })(TaigaBase);\n\n this.taiga.Base = TaigaBase;\n\n this.taiga.Service = TaigaService;\n\n this.taiga.Controller = TaigaController;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: utils.coffee\n */\n\n(function() {\n var bindMethods, bindOnce, cancelTimeout, debounce, debounceLeading, groupBy, joinStr, mixOf, nl2br, scopeDefer, sizeFormat, slugify, startswith, taiga, timeout, toString, toggleText, trim, unslugify,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },\n __slice = [].slice,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n nl2br = (function(_this) {\n return function(str) {\n var breakTag;\n breakTag = '
    ';\n return (str + '').replace(/([^>\\r\\n]?)(\\r\\n|\\n\\r|\\r|\\n)/g, '$1' + breakTag + '$2');\n };\n })(this);\n\n bindMethods = (function(_this) {\n return function(object) {\n var dependencies, methods;\n dependencies = _.keys(object);\n methods = [];\n _.forIn(object, function(value, key) {\n if (__indexOf.call(dependencies, key) < 0) {\n return methods.push(key);\n }\n });\n return _.bindAll(object, methods);\n };\n })(this);\n\n bindOnce = (function(_this) {\n return function(scope, attr, continuation) {\n var delBind, val;\n val = scope.$eval(attr);\n if (val !== void 0) {\n return continuation(val);\n }\n delBind = null;\n return delBind = scope.$watch(attr, function(val) {\n if (val === void 0) {\n return;\n }\n continuation(val);\n if (delBind) {\n return delBind();\n }\n });\n };\n })(this);\n\n mixOf = function() {\n var Mixed, base, method, mixin, mixins, name, _i, _ref;\n base = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n Mixed = (function(_super) {\n __extends(Mixed, _super);\n\n function Mixed() {\n return Mixed.__super__.constructor.apply(this, arguments);\n }\n\n return Mixed;\n\n })(base);\n for (_i = mixins.length - 1; _i >= 0; _i += -1) {\n mixin = mixins[_i];\n _ref = mixin.prototype;\n for (name in _ref) {\n method = _ref[name];\n Mixed.prototype[name] = method;\n }\n }\n return Mixed;\n };\n\n trim = function(data, char) {\n return _.str.trim(data, char);\n };\n\n slugify = function(data) {\n return _.str.slugify(data);\n };\n\n unslugify = function(data) {\n if (data) {\n return _.str.capitalize(data.replace(/-/g, ' '));\n }\n return data;\n };\n\n toggleText = function(element, texts) {\n var nextTextPosition, text;\n nextTextPosition = element.data('nextTextPosition');\n if ((nextTextPosition == null) || nextTextPosition >= texts.length) {\n nextTextPosition = 0;\n }\n text = texts[nextTextPosition];\n element.data('nextTextPosition', nextTextPosition + 1);\n return element.text(text);\n };\n\n groupBy = function(coll, pred) {\n var item, result, _i, _len;\n result = {};\n for (_i = 0, _len = coll.length; _i < _len; _i++) {\n item = coll[_i];\n result[pred(item)] = item;\n }\n return result;\n };\n\n timeout = function(wait, continuation) {\n return window.setTimeout(continuation, wait);\n };\n\n cancelTimeout = function(timeoutVar) {\n return window.clearTimeout(timeoutVar);\n };\n\n scopeDefer = function(scope, func) {\n return _.defer((function(_this) {\n return function() {\n return scope.$apply(func);\n };\n })(this));\n };\n\n toString = function(value) {\n if (_.isNumber(value)) {\n return value + \"\";\n } else if (_.isString(value)) {\n return value;\n } else if (_.isPlainObject(value)) {\n return JSON.stringify(value);\n } else if (_.isUndefined(value)) {\n return \"\";\n }\n return value.toString();\n };\n\n joinStr = function(str, coll) {\n return _.str.join(str, coll);\n };\n\n debounce = function(wait, func) {\n return _.debounce(func, wait, {\n leading: true,\n trailing: false\n });\n };\n\n debounceLeading = function(wait, func) {\n return _.debounce(func, wait, {\n leading: false,\n trailing: true\n });\n };\n\n startswith = function(str1, str2) {\n return _.str.startsWith(str1, str2);\n };\n\n sizeFormat = function(input, precision) {\n var number, size, units;\n if (precision == null) {\n precision = 1;\n }\n if (isNaN(parseFloat(input)) || !isFinite(input)) {\n return \"-\";\n }\n if (input === 0) {\n return \"0 bytes\";\n }\n units = [\"bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n number = Math.floor(Math.log(input) / Math.log(1024));\n if (number > 5) {\n number = 5;\n }\n size = (input / Math.pow(1024, number)).toFixed(precision);\n return \"\" + size + \" \" + units[number];\n };\n\n taiga = this.taiga;\n\n taiga.nl2br = nl2br;\n\n taiga.bindMethods = bindMethods;\n\n taiga.bindOnce = bindOnce;\n\n taiga.mixOf = mixOf;\n\n taiga.trim = trim;\n\n taiga.slugify = slugify;\n\n taiga.unslugify = unslugify;\n\n taiga.toggleText = toggleText;\n\n taiga.groupBy = groupBy;\n\n taiga.timeout = timeout;\n\n taiga.cancelTimeout = cancelTimeout;\n\n taiga.scopeDefer = scopeDefer;\n\n taiga.toString = toString;\n\n taiga.joinStr = joinStr;\n\n taiga.debounce = debounce;\n\n taiga.debounceLeading = debounceLeading;\n\n taiga.startswith = startswith;\n\n taiga.sizeFormat = sizeFormat;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/controllerMixins.coffee\n */\n\n(function() {\n var FiltersMixin, PageMixin, groupBy, joinStr, taiga, toString, trim;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n joinStr = this.taiga.joinStr;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n PageMixin = (function() {\n function PageMixin() {}\n\n PageMixin.prototype.fillUsersAndRoles = function(users, roles) {\n var activeUsers, availableRoles;\n activeUsers = _.filter(users, (function(_this) {\n return function(user) {\n return user.is_active;\n };\n })(this));\n this.scope.activeUsers = _.sortBy(activeUsers, \"full_name_display\");\n this.scope.activeUsersById = groupBy(this.scope.activeUsers, function(e) {\n return e.id;\n });\n this.scope.users = _.sortBy(users, \"full_name_display\");\n this.scope.usersById = groupBy(this.scope.users, function(e) {\n return e.id;\n });\n this.scope.roles = _.sortBy(roles, \"order\");\n availableRoles = _(this.scope.project.memberships).map(\"role\").uniq().value();\n return this.scope.computableRoles = _(roles).filter(\"computable\").filter(function(x) {\n return _.contains(availableRoles, x.id);\n }).value();\n };\n\n PageMixin.prototype.loadUsersAndRoles = function() {\n var promise;\n promise = this.q.all([this.rs.projects.usersList(this.scope.projectId), this.rs.projects.rolesList(this.scope.projectId)]);\n return promise.then((function(_this) {\n return function(results) {\n var roles, users;\n users = results[0], roles = results[1];\n _this.fillUsersAndRoles(users, roles);\n return results;\n };\n })(this));\n };\n\n return PageMixin;\n\n })();\n\n taiga.PageMixin = PageMixin;\n\n FiltersMixin = (function() {\n function FiltersMixin() {}\n\n FiltersMixin.prototype.selectFilter = function(name, value, load) {\n var existing, location, params;\n if (load == null) {\n load = false;\n }\n params = this.location.search();\n if (params[name] !== void 0 && name !== \"page\") {\n existing = _.map(taiga.toString(params[name]).split(\",\"), function(x) {\n return trim(x);\n });\n existing.push(taiga.toString(value));\n existing = _.compact(existing);\n value = joinStr(\",\", _.uniq(existing));\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n FiltersMixin.prototype.replaceFilter = function(name, value, load) {\n var location;\n if (load == null) {\n load = false;\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n FiltersMixin.prototype.replaceAllFilters = function(filters, load) {\n var location;\n if (load == null) {\n load = false;\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(filters);\n };\n\n FiltersMixin.prototype.unselectFilter = function(name, value, load) {\n var location, newValues, params, parsedValues;\n if (load == null) {\n load = false;\n }\n params = this.location.search();\n if (params[name] === void 0) {\n return;\n }\n if (value === void 0 || value === null) {\n delete params[name];\n }\n parsedValues = _.map(taiga.toString(params[name]).split(\",\"), function(x) {\n return trim(x);\n });\n newValues = _.reject(parsedValues, function(x) {\n return x === taiga.toString(value);\n });\n newValues = _.compact(newValues);\n if (_.isEmpty(newValues)) {\n value = null;\n } else {\n value = joinStr(\",\", _.uniq(newValues));\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n return FiltersMixin;\n\n })();\n\n taiga.FiltersMixin = FiltersMixin;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaAdmin\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/auth.coffee\n */\n\n(function() {\n var AuthService, CancelAccountDirective, ChangeEmailDirective, ChangePasswordFromRecoveryDirective, ForgotPasswordDirective, InvitationDirective, LoginDirective, PublicRegisterMessageDirective, RegisterDirective, debounce, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAuth\", [\"taigaResources\"]);\n\n AuthService = (function(_super) {\n __extends(AuthService, _super);\n\n AuthService.$inject = [\"$rootScope\", \"$tgStorage\", \"$tgModel\", \"$tgResources\", \"$tgHttp\", \"$tgUrls\"];\n\n function AuthService(rootscope, storage, model, rs, http, urls) {\n this.rootscope = rootscope;\n this.storage = storage;\n this.model = model;\n this.rs = rs;\n this.http = http;\n this.urls = urls;\n AuthService.__super__.constructor.call(this);\n }\n\n AuthService.prototype.getUser = function() {\n var user, userData;\n if (this.rootscope.user) {\n return this.rootscope.user;\n }\n userData = this.storage.get(\"userInfo\");\n if (userData) {\n user = this.model.make_model(\"users\", userData);\n this.rootscope.user = user;\n return user;\n }\n return null;\n };\n\n AuthService.prototype.setUser = function(user) {\n this.rootscope.auth = user;\n this.rootscope.$broadcast(\"i18n:change\", user.default_language);\n this.storage.set(\"userInfo\", user.getAttrs());\n return this.rootscope.user = user;\n };\n\n AuthService.prototype.clear = function() {\n this.rootscope.auth = null;\n this.rootscope.user = null;\n return this.storage.remove(\"userInfo\");\n };\n\n AuthService.prototype.setToken = function(token) {\n return this.storage.set(\"token\", token);\n };\n\n AuthService.prototype.getToken = function() {\n return this.storage.get(\"token\");\n };\n\n AuthService.prototype.removeToken = function() {\n return this.storage.remove(\"token\");\n };\n\n AuthService.prototype.isAuthenticated = function() {\n if (this.getUser() !== null) {\n return true;\n }\n return false;\n };\n\n AuthService.prototype.login = function(data, type) {\n var url;\n url = this.urls.resolve(\"auth\");\n data = _.clone(data, false);\n data.type = type ? type : \"normal\";\n this.removeToken();\n return this.http.post(url, data).then((function(_this) {\n return function(data, status) {\n var user;\n user = _this.model.make_model(\"users\", data.data);\n _this.setToken(user.auth_token);\n _this.setUser(user);\n return user;\n };\n })(this));\n };\n\n AuthService.prototype.logout = function() {\n this.removeToken();\n return this.clear();\n };\n\n AuthService.prototype.register = function(data, type, existing) {\n var url;\n url = this.urls.resolve(\"auth-register\");\n data = _.clone(data, false);\n data.type = type ? type : \"public\";\n if (type === \"private\") {\n data.existing = existing ? existing : false;\n }\n this.removeToken();\n return this.http.post(url, data).then((function(_this) {\n return function(response) {\n var user;\n user = _this.model.make_model(\"users\", response.data);\n _this.setToken(user.auth_token);\n _this.setUser(user);\n return user;\n };\n })(this));\n };\n\n AuthService.prototype.getInvitation = function(token) {\n return this.rs.invitations.get(token);\n };\n\n AuthService.prototype.acceptInvitiationWithNewUser = function(data) {\n return this.register(data, \"private\", false);\n };\n\n AuthService.prototype.acceptInvitiationWithExistingUser = function(data) {\n return this.register(data, \"private\", true);\n };\n\n AuthService.prototype.forgotPassword = function(data) {\n var url;\n url = this.urls.resolve(\"users-password-recovery\");\n data = _.clone(data, false);\n this.removeToken();\n return this.http.post(url, data);\n };\n\n AuthService.prototype.changePasswordFromRecovery = function(data) {\n var url;\n url = this.urls.resolve(\"users-change-password-from-recovery\");\n data = _.clone(data, false);\n this.removeToken();\n return this.http.post(url, data);\n };\n\n AuthService.prototype.changeEmail = function(data) {\n var url;\n url = this.urls.resolve(\"users-change-email\");\n data = _.clone(data, false);\n return this.http.post(url, data);\n };\n\n AuthService.prototype.cancelAccount = function(data) {\n var url;\n url = this.urls.resolve(\"users-cancel-account\");\n data = _.clone(data, false);\n return this.http.post(url, data);\n };\n\n return AuthService;\n\n })(taiga.Service);\n\n module.service(\"$tgAuth\", AuthService);\n\n PublicRegisterMessageDirective = function($config, $navUrls) {\n var template, templateFn;\n template = _.template(\"

    \\n Not registered yet?\\n \\\" tg-nav=\\\"register\\\" title=\\\"Register\\\"> create your free account here\\n

    \");\n templateFn = function() {\n var publicRegisterEnabled;\n publicRegisterEnabled = $config.get(\"publicRegisterEnabled\");\n if (!publicRegisterEnabled) {\n return \"\";\n }\n return template({\n url: $navUrls.resolve(\"register\")\n });\n };\n return {\n restrict: \"AE\",\n scope: {},\n template: templateFn\n };\n };\n\n module.directive(\"tgPublicRegisterMessage\", [\"$tgConfig\", \"$tgNavUrls\", PublicRegisterMessageDirective]);\n\n LoginDirective = function($auth, $confirm, $location, $config, $routeParams, $navUrls, $events) {\n var link;\n link = function($scope, $el, $attrs) {\n var onError, onSuccess, submit;\n onSuccess = function(response) {\n var nextUrl;\n if ($routeParams['next'] && $routeParams['next'] !== $navUrls.resolve(\"login\")) {\n nextUrl = $routeParams['next'];\n } else {\n nextUrl = $navUrls.resolve(\"home\");\n }\n $events.setupConnection();\n return $location.path(nextUrl);\n };\n onError = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your username/email or password are incorrect.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, promise;\n event.preventDefault();\n form = new checksley.Form($el.find(\"form.login-form\"));\n if (!form.validate()) {\n return;\n }\n data = {\n \"username\": $el.find(\"form.login-form input[name=username]\").val(),\n \"password\": $el.find(\"form.login-form input[name=password]\").val()\n };\n promise = $auth.login(data);\n return promise.then(onSuccess, onError);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLogin\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgConfig\", \"$routeParams\", \"$tgNavUrls\", \"$tgEvents\", LoginDirective]);\n\n RegisterDirective = function($auth, $confirm, $location, $navUrls, $config, $analytics) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n if (!$config.get(\"publicRegisterEnabled\")) {\n $location.path($navUrls.resolve(\"not-found\"));\n $location.replace();\n }\n $scope.data = {};\n form = $el.find(\"form\").checksley({\n onlyOneErrorElement: true\n });\n onSuccessSubmit = function(response) {\n $analytics.trackEvent(\"auth\", \"register\", \"user registration\", 1);\n $confirm.notify(\"success\", \"Our Oompa Loompas are happy, welcome to Taiga.\");\n return $location.path($navUrls.resolve(\"home\"));\n };\n onErrorSubmit = function(response) {\n if (response.data._error_message != null) {\n $confirm.notify(\"light-error\", \"According to our Oompa Loompas there was an error. \" + response.data._error_message);\n }\n return form.setErrors(response.data);\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.register($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRegister\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfig\", \"$tgAnalytics\", RegisterDirective]);\n\n ForgotPasswordDirective = function($auth, $confirm, $location, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Check your inbox!
    We have sent a mail to
    \" + response.data.email + \"
    with the instructions to set a new password\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your are not registered yet.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.forgotPassword($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgForgotPassword\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgNavUrls\", ForgotPasswordDirective]);\n\n ChangePasswordFromRecoveryDirective = function($auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n if ($params.token != null) {\n $scope.tokenInParams = true;\n $scope.data.token = $params.token;\n } else {\n $scope.tokenInParams = false;\n }\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Our Oompa Loompas saved your new password.
    Try to sign in with it.\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"light-error\", \"One of our Oompa Loompas say '\" + response.data._error_message + \"'.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.changePasswordFromRecovery($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgChangePasswordFromRecovery\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", ChangePasswordFromRecoveryDirective]);\n\n InvitationDirective = function($auth, $confirm, $location, $params, $navUrls, $analytics) {\n var link;\n link = function($scope, $el, $attrs) {\n var loginForm, onErrorSubmitLogin, onErrorSubmitRegister, onSuccessSubmitLogin, onSuccessSubmitRegister, promise, registerForm, submitLogin, submitRegister, token;\n token = $params.token;\n promise = $auth.getInvitation(token);\n promise.then(function(invitation) {\n return $scope.invitation = invitation;\n });\n promise.then(null, function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Ooops, we have a problem
    Our Oompa Loompas can't find your invitation.\");\n });\n $scope.dataLogin = {\n token: token\n };\n loginForm = $el.find(\"form.login-form\").checksley({\n onlyOneErrorElement: true\n });\n onSuccessSubmitLogin = function(response) {\n $analytics.trackEvent(\"auth\", \"invitationAccept\", \"invitation accept with existing user\", 1);\n $location.path($navUrls.resolve(\"project\", {\n project: $scope.invitation.project_slug\n }));\n return $confirm.notify(\"success\", \"You've successfully joined this project\", \"Welcome to \" + (_.escape($scope.invitation.project_name)));\n };\n onErrorSubmitLogin = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your are not registered yet or typed an invalid password.\");\n };\n submitLogin = debounce(2000, (function(_this) {\n return function(event) {\n event.preventDefault();\n if (!loginForm.validate()) {\n return;\n }\n promise = $auth.acceptInvitiationWithExistingUser($scope.dataLogin);\n return promise.then(onSuccessSubmitLogin, onErrorSubmitLogin);\n };\n })(this));\n $el.on(\"submit\", \"form.login-form\", submitLogin);\n $el.on(\"click\", \".button-login\", submitLogin);\n $scope.dataRegister = {\n token: token\n };\n registerForm = $el.find(\"form.register-form\").checksley();\n onSuccessSubmitRegister = function(response) {\n $analytics.trackEvent(\"auth\", \"invitationAccept\", \"invitation accept with new user\", 1);\n $location.path($navUrls.resolve(\"project\", {\n project: $scope.invitation.project_slug\n }));\n return $confirm.notify(\"success\", \"You've successfully joined this project\", \"Welcome to \" + (_.escape($scope.invitation.project_name)));\n };\n onErrorSubmitRegister = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, that username or email is already in use.\");\n };\n submitRegister = debounce(2000, (function(_this) {\n return function(event) {\n event.preventDefault();\n if (!registerForm.validate()) {\n return;\n }\n promise = $auth.acceptInvitiationWithNewUser($scope.dataRegister);\n return promise.then(onSuccessSubmitRegister, onErrorSubmitRegister);\n };\n })(this));\n $el.on(\"submit\", \"form.register-form\", submitRegister);\n return $el.on(\"click\", \".button-register\", submitRegister);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgInvitation\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", \"$tgAnalytics\", InvitationDirective]);\n\n ChangeEmailDirective = function($repo, $model, $auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n $scope.data.email_token = $params.email_token;\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n return $repo.queryOne(\"users\", $auth.getUser().id).then((function(_this) {\n return function(data) {\n $auth.setUser(data);\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.success(\"Our Oompa Loompas updated your email\");\n };\n })(this));\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"error\", \"One of our Oompa Loompas says '\" + response.data._error_message + \"'.\");\n };\n submit = function() {\n var promise;\n if (!form.validate()) {\n return;\n }\n promise = $auth.changeEmail($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n $el.on(\"submit\", function(event) {\n event.preventDefault();\n return submit();\n });\n return $el.on(\"click\", \"a.button-change-email\", function(event) {\n event.preventDefault();\n return submit();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgChangeEmail\", [\"$tgRepo\", \"$tgModel\", \"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", ChangeEmailDirective]);\n\n CancelAccountDirective = function($repo, $model, $auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n $scope.data.cancel_token = $params.cancel_token;\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $auth.logout();\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.success(\"Our Oompa Loompas removed your account\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"error\", \"One of our Oompa Loompas says '\" + response.data._error_message + \"'.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.cancelAccount($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgCancelAccount\", [\"$tgRepo\", \"$tgModel\", \"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", CancelAccountDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaBacklog\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base.coffee\n */\n\n(function() {\n var TaigaMainDirective, bindOnce, groupBy, init, module, taiga, urls;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaBase\", [\"taigaLocales\"]);\n\n TaigaMainDirective = function($rootscope, $window) {\n var link;\n link = function($scope, $el, $attrs) {\n return $window.onresize = function() {\n return $rootscope.$broadcast(\"resize\");\n };\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMain\", [\"$rootScope\", \"$window\", TaigaMainDirective]);\n\n urls = {\n \"home\": \"/\",\n \"error\": \"/error\",\n \"not-found\": \"/not-found\",\n \"permission-denied\": \"/permission-denied\",\n \"login\": \"/login\",\n \"forgot-password\": \"/forgot-password\",\n \"change-password\": \"/change-password/:token\",\n \"change-email\": \"/change-email/:token\",\n \"cancel-account\": \"/cancel-account/:token\",\n \"register\": \"/register\",\n \"invitation\": \"/invitation/:token\",\n \"create-project\": \"/create-project\",\n \"profile\": \"/:user\",\n \"project\": \"/project/:project\",\n \"project-backlog\": \"/project/:project/backlog\",\n \"project-taskboard\": \"/project/:project/taskboard/:sprint\",\n \"project-kanban\": \"/project/:project/kanban\",\n \"project-issues\": \"/project/:project/issues\",\n \"project-search\": \"/project/:project/search\",\n \"project-userstories-detail\": \"/project/:project/us/:ref\",\n \"project-tasks-detail\": \"/project/:project/task/:ref\",\n \"project-issues-detail\": \"/project/:project/issue/:ref\",\n \"project-wiki\": \"/project/:project/wiki\",\n \"project-wiki-page\": \"/project/:project/wiki/:slug\",\n \"project-team\": \"/project/:project/team\",\n \"project-admin-home\": \"/project/:project/admin/project-profile/details\",\n \"project-admin-project-profile-details\": \"/project/:project/admin/project-profile/details\",\n \"project-admin-project-profile-default-values\": \"/project/:project/admin/project-profile/default-values\",\n \"project-admin-project-profile-modules\": \"/project/:project/admin/project-profile/modules\",\n \"project-admin-project-values-us-status\": \"/project/:project/admin/project-values/us-status\",\n \"project-admin-project-values-us-points\": \"/project/:project/admin/project-values/us-points\",\n \"project-admin-project-values-task-status\": \"/project/:project/admin/project-values/task-status\",\n \"project-admin-project-values-issue-status\": \"/project/:project/admin/project-values/issue-status\",\n \"project-admin-project-values-issue-types\": \"/project/:project/admin/project-values/issue-types\",\n \"project-admin-project-values-issue-priorities\": \"/project/:project/admin/project-values/issue-priorities\",\n \"project-admin-project-values-issue-severities\": \"/project/:project/admin/project-values/issue-severities\",\n \"project-admin-memberships\": \"/project/:project/admin/memberships\",\n \"project-admin-roles\": \"/project/:project/admin/roles\",\n \"project-admin-third-parties-github\": \"/project/:project/admin/third-parties/github\",\n \"project-admin-third-parties-gitlab\": \"/project/:project/admin/third-parties/gitlab\",\n \"project-admin-third-parties-bitbucket\": \"/project/:project/admin/third-parties/bitbucket\",\n \"project-admin-contrib\": \"/project/:project/admin/contrib/:plugin\",\n \"user-settings-user-profile\": \"/project/:project/user-settings/user-profile\",\n \"user-settings-user-change-password\": \"/project/:project/user-settings/user-change-password\",\n \"user-settings-user-avatar\": \"/project/:project/user-settings/user-avatar\",\n \"user-settings-mail-notifications\": \"/project/:project/user-settings/mail-notifications\"\n };\n\n init = function($log, $navurls) {\n $log.debug(\"Initialize navigation urls\");\n return $navurls.update(urls);\n };\n\n module.run([\"$log\", \"$tgNavUrls\", init]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common.coffee\n */\n\n(function() {\n var AnimationFrame, AppTitle, CheckPermissionDirective, LimitLineLengthDirective, ProjectUrl, Qqueue, SelectedText, ToggleCommentDirective, module, taiga,\n __slice = [].slice;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\", []);\n\n SelectedText = function($window, $document) {\n var get;\n get = function() {\n if ($window.getSelection) {\n return $window.getSelection().toString();\n } else if ($document.selection) {\n return $document.selection.createRange().text;\n }\n return \"\";\n };\n return {\n get: get\n };\n };\n\n module.factory(\"$selectedText\", [\"$window\", \"$document\", SelectedText]);\n\n CheckPermissionDirective = function() {\n var link, render;\n render = function($el, project, permission) {\n if (project.my_permissions.indexOf(permission) > -1) {\n return $el.removeClass('hidden');\n }\n };\n link = function($scope, $el, $attrs) {\n var permission;\n $el.addClass('hidden');\n permission = $attrs.tgCheckPermission;\n $scope.$watch(\"project\", function(project) {\n if (project != null) {\n return render($el, project, permission);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgCheckPermission\", CheckPermissionDirective);\n\n AnimationFrame = function() {\n var add, animationFrame, performAnimation, tail;\n animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;\n performAnimation = (function(_this) {\n return function(time) {\n var fn;\n fn = tail.shift();\n fn();\n if (tail.length) {\n return animationFrame(performAnimation);\n }\n };\n })(this);\n tail = [];\n add = function() {\n var fn, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = arguments.length; _i < _len; _i++) {\n fn = arguments[_i];\n tail.push(fn);\n if (tail.length === 1) {\n _results.push(animationFrame(performAnimation));\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n };\n return {\n add: add\n };\n };\n\n module.factory(\"animationFrame\", AnimationFrame);\n\n ToggleCommentDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.find(\"textarea\").on(\"focus\", function() {\n return $el.addClass(\"active\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgToggleComment\", ToggleCommentDirective);\n\n AppTitle = function() {\n var set;\n set = function(text) {\n return $(\"title\").text(text);\n };\n return {\n set: set\n };\n };\n\n module.factory(\"$appTitle\", AppTitle);\n\n ProjectUrl = function($navurls) {\n var get;\n get = function(project) {\n var ctx;\n ctx = {\n project: project.slug\n };\n if (project.is_backlog_activated && project.my_permissions.indexOf(\"view_us\") > -1) {\n return $navurls.resolve(\"project-backlog\", ctx);\n }\n if (project.is_kanban_activated && project.my_permissions.indexOf(\"view_us\") > -1) {\n return $navurls.resolve(\"project-kanban\", ctx);\n }\n if (project.is_wiki_activated && project.my_permissions.indexOf(\"view_wiki_pages\") > -1) {\n return $navurls.resolve(\"project-wiki\", ctx);\n }\n if (project.is_issues_activated && project.my_permissions.indexOf(\"view_issues\") > -1) {\n return $navurls.resolve(\"project-issues\", ctx);\n }\n return $navurls.resolve(\"project\", ctx);\n };\n return {\n get: get\n };\n };\n\n module.factory(\"$projectUrl\", [\"$tgNavUrls\", ProjectUrl]);\n\n LimitLineLengthDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var maxColsPerLine;\n maxColsPerLine = parseInt($el.attr(\"cols\"));\n return $el.on(\"keyup\", function(event) {\n var code, lines;\n code = event.keyCode;\n lines = $el.val().split(\"\\n\");\n _.each(lines, function(line, index) {\n return lines[index] = line.substring(0, maxColsPerLine - 2);\n });\n return $el.val(lines.join(\"\\n\"));\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLimitLineLength\", LimitLineLengthDirective);\n\n Qqueue = function($q) {\n var deferred, lastPromise, qqueue;\n deferred = $q.defer();\n deferred.resolve();\n lastPromise = deferred.promise;\n qqueue = {\n bindAdd: (function(_this) {\n return function(fn) {\n return function() {\n var args;\n args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];\n return lastPromise = lastPromise.then(function() {\n return fn.apply(_this, args);\n });\n };\n return qqueue;\n };\n })(this),\n add: (function(_this) {\n return function(fn) {\n if (!lastPromise) {\n lastPromise = fn();\n } else {\n lastPromise = lastPromise.then(fn);\n }\n return qqueue;\n };\n })(this)\n };\n return qqueue;\n };\n\n module.factory(\"$tgQqueue\", [\"$q\", Qqueue]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/events.coffee\n */\n\n(function() {\n var EventsProvider, EventsService, bindMethods, module, startswith, taiga;\n\n taiga = this.taiga;\n\n startswith = this.taiga.startswith;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaEvents\", []);\n\n EventsService = (function() {\n function EventsService(win, log, config, auth) {\n this.win = win;\n this.log = log;\n this.config = config;\n this.auth = auth;\n bindMethods(this);\n }\n\n EventsService.prototype.initialize = function(sessionId) {\n this.sessionId = sessionId;\n this.subscriptions = {};\n this.connected = false;\n this.error = false;\n this.pendingMessages = [];\n if (this.win.WebSocket === void 0) {\n return this.log.info(\"WebSockets not supported on your browser\");\n }\n };\n\n EventsService.prototype.setupConnection = function() {\n var loc, path, scheme, url;\n this.stopExistingConnection();\n url = this.config.get(\"eventsUrl\");\n if (!url) {\n return;\n }\n if (!startswith(url, \"ws:\") && !startswith(url, \"wss:\")) {\n loc = this.win.location;\n scheme = loc.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n path = _.str.ltrim(url, \"/\");\n url = \"\" + scheme + \"//\" + loc.host + \"/\" + path;\n }\n this.ws = new this.win.WebSocket(url);\n this.ws.addEventListener(\"open\", this.onOpen);\n this.ws.addEventListener(\"message\", this.onMessage);\n this.ws.addEventListener(\"error\", this.onError);\n return this.ws.addEventListener(\"close\", this.onClose);\n };\n\n EventsService.prototype.stopExistingConnection = function() {\n if (this.ws === void 0) {\n return;\n }\n this.ws.removeEventListener(\"open\", this.onOpen);\n this.ws.removeEventListener(\"close\", this.onClose);\n this.ws.removeEventListener(\"error\", this.onError);\n this.ws.removeEventListener(\"message\", this.onMessage);\n this.ws.close();\n return delete this.ws;\n };\n\n EventsService.prototype.serialize = function(message) {\n if (_.isObject(message)) {\n return JSON.stringify(message);\n }\n return message;\n };\n\n EventsService.prototype.sendMessage = function(message) {\n var messages, msg, _i, _len, _results;\n this.pendingMessages.push(message);\n if (!this.connected) {\n return;\n }\n messages = _.map(this.pendingMessages, this.serialize);\n this.pendingMessages = [];\n _results = [];\n for (_i = 0, _len = messages.length; _i < _len; _i++) {\n msg = messages[_i];\n _results.push(this.ws.send(msg));\n }\n return _results;\n };\n\n EventsService.prototype.subscribe = function(scope, routingKey, callback) {\n var message, subscription;\n if (this.error) {\n return;\n }\n this.log.debug(\"Subscribe to: \" + routingKey);\n subscription = {\n scope: scope,\n routingKey: routingKey,\n callback: _.debounce(callback, 500, {\n \"leading\": true,\n \"trailing\": false\n })\n };\n message = {\n \"cmd\": \"subscribe\",\n \"routing_key\": routingKey\n };\n this.subscriptions[routingKey] = subscription;\n this.sendMessage(message);\n return scope.$on(\"$destroy\", (function(_this) {\n return function() {\n return _this.unsubscribe(routingKey);\n };\n })(this));\n };\n\n EventsService.prototype.unsubscribe = function(routingKey) {\n var message;\n if (this.error) {\n return;\n }\n this.log.debug(\"Unsubscribe from: \" + routingKey);\n message = {\n \"cmd\": \"unsubscribe\",\n \"routing_key\": routingKey\n };\n return this.sendMessage(message);\n };\n\n EventsService.prototype.onOpen = function() {\n var message, token;\n this.connected = true;\n this.log.debug(\"WebSocket connection opened\");\n token = this.auth.getToken();\n message = {\n cmd: \"auth\",\n data: {\n token: token,\n sessionId: this.sessionId\n }\n };\n return this.sendMessage(message);\n };\n\n EventsService.prototype.onMessage = function(event) {\n var data, routingKey, subscription;\n this.log.debug(\"WebSocket message received: \" + event.data);\n data = JSON.parse(event.data);\n routingKey = data.routing_key;\n if (this.subscriptions[routingKey] == null) {\n return;\n }\n subscription = this.subscriptions[routingKey];\n return subscription.scope.$apply(function() {\n return subscription.callback(data.data);\n });\n };\n\n EventsService.prototype.onError = function(error) {\n this.log.error(\"WebSocket error: \" + error);\n return this.error = true;\n };\n\n EventsService.prototype.onClose = function() {\n this.log.debug(\"WebSocket closed.\");\n return this.connected = false;\n };\n\n return EventsService;\n\n })();\n\n EventsProvider = (function() {\n function EventsProvider() {}\n\n EventsProvider.prototype.setSessionId = function(sessionId) {\n return this.sessionId = sessionId;\n };\n\n EventsProvider.prototype.$get = function($win, $log, $conf, $auth) {\n var service;\n service = new EventsService($win, $log, $conf, $auth);\n service.initialize(this.sessionId);\n return service;\n };\n\n EventsProvider.prototype.$get.$inject = [\"$window\", \"$log\", \"$tgConfig\", \"$tgAuth\"];\n\n return EventsProvider;\n\n })();\n\n module.provider(\"$tgEvents\", EventsProvider);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/feedback.coffee\n */\n\n(function() {\n var FeedbackDirective, bindOnce, debounce, groupBy, mixOf, module, taiga, trim;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n mixOf = this.taiga.mixOf;\n\n debounce = this.taiga.debounce;\n\n trim = this.taiga.trim;\n\n module = angular.module(\"taigaFeedback\", []);\n\n FeedbackDirective = function($lightboxService, $repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley();\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"feedback\", $scope.feedback);\n promise.then(function(data) {\n $loading.finish(submitButton);\n $lightboxService.close($el);\n return $confirm.notify(\"success\", \"\\\\o/ we'll be happy to read your\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $scope.$on(\"feedback:show\", function() {\n $scope.$apply(function() {\n return $scope.feedback = {};\n });\n $lightboxService.open($el);\n return $el.find(\"textarea\").focus();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbFeedback\", [\"lightboxService\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", FeedbackDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/integrations.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaIntegrations\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaIssues\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaKanban\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/locales.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaLocales\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/nav.coffee\n */\n\n(function() {\n var ProjectMenuDirective, ProjectsNavigationController, ProjectsNavigationDirective, bindOnce, groupBy, module, taiga, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaNavMenu\", []);\n\n ProjectsNavigationController = (function(_super) {\n __extends(ProjectsNavigationController, _super);\n\n ProjectsNavigationController.$inject = [\"$scope\", \"$rootScope\", \"$tgResources\", \"$tgNavUrls\", \"$projectUrl\"];\n\n function ProjectsNavigationController(scope, rootscope, rs, navurls, projectUrl) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.rs = rs;\n this.navurls = navurls;\n this.projectUrl = projectUrl;\n promise = this.loadInitialData();\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n this.scope.$on(\"projects:reload\", (function(_this) {\n return function() {\n return _this.loadInitialData();\n };\n })(this));\n this.scope.$on(\"project:loaded\", (function(_this) {\n return function(ctx, project) {\n return _this.loadInitialData();\n };\n })(this));\n }\n\n ProjectsNavigationController.prototype.loadInitialData = function() {\n return this.rs.projects.list().then((function(_this) {\n return function(projects) {\n var project, _i, _len;\n for (_i = 0, _len = projects.length; _i < _len; _i++) {\n project = projects[_i];\n project.url = _this.projectUrl.get(project);\n }\n _this.scope.projects = projects;\n _this.scope.filteredProjects = projects;\n _this.scope.filterText = \"\";\n return projects;\n };\n })(this));\n };\n\n ProjectsNavigationController.prototype.newProject = function() {\n return this.scope.$apply((function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"projects:create\");\n };\n })(this));\n };\n\n ProjectsNavigationController.prototype.filterProjects = function(text) {\n this.scope.filteredProjects = _.filter(this.scope.projects, function(project) {\n return project.name.toLowerCase().indexOf(text) > -1;\n });\n this.scope.filterText = text;\n return this.rootscope.$broadcast(\"projects:filtered\");\n };\n\n return ProjectsNavigationController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectsNavigationController\", ProjectsNavigationController);\n\n ProjectsNavigationDirective = function($rootscope, animationFrame, $timeout, tgLoader, $location, $compile) {\n var baseTemplate, hideMenu, link, loadingStart, overlay, projectsTemplate;\n baseTemplate = _.template(\"

    Your projects

    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n\\n\\n\\n
    \\n \\n
    \\n
      \\n
    \\n
    \\n \\n
    \");\n projectsTemplate = _.template(\"<% _.each(projects, function(project) { %>\\n
  • \\n \\\">\\n <%- project.name %>\\n \\n \\n
  • \\n<% }) %>\");\n overlay = $(\".projects-nav-overlay\");\n loadingStart = 0;\n hideMenu = function() {\n var difftime, timeoutValue;\n if (overlay.is(':visible')) {\n difftime = new Date().getTime() - loadingStart;\n timeoutValue = 0;\n if (difftime < 1000) {\n timeoutValue = 1000 - timeoutValue;\n }\n return timeout(timeoutValue, function() {\n overlay.one('transitionend', function() {\n $(document.body).removeClass(\"loading-project open-projects-nav closed-projects-nav\").css(\"overflow-x\", \"visible\");\n return overlay.hide();\n });\n $(document.body).addClass(\"closed-projects-nav\");\n return tgLoader.disablePreventLoading();\n });\n }\n };\n link = function($scope, $el, $attrs, $ctrls) {\n var $ctrl, render, renderProjects;\n $ctrl = $ctrls[0];\n $rootscope.$on(\"project:loaded\", hideMenu);\n renderProjects = function(projects) {\n var html;\n html = projectsTemplate({\n projects: projects\n });\n $el.find(\".projects-list\").html(html);\n return $scope.$emit(\"regenerate:project-pagination\");\n };\n render = function(projects) {\n $el.html($compile(baseTemplate())($scope));\n return renderProjects(projects);\n };\n overlay.on('click', function() {\n return hideMenu();\n });\n $(document).on('keydown', (function(_this) {\n return function(e) {\n var code;\n code = e.keyCode ? e.keyCode : e.which;\n if (code === 27) {\n return hideMenu();\n }\n };\n })(this));\n $scope.$on(\"nav:projects-list:open\", function() {\n if (!$(document.body).hasClass(\"open-projects-nav\")) {\n animationFrame.add((function(_this) {\n return function() {\n return overlay.show();\n };\n })(this));\n }\n return animationFrame.add((function(_this) {\n return function() {\n return $(document.body).css(\"overflow-x\", \"hidden\");\n };\n })(this), (function(_this) {\n return function() {\n return $(document.body).toggleClass(\"open-projects-nav\");\n };\n })(this));\n });\n $el.on(\"click\", \".projects-list > li > a\", function(event) {\n var currentUrl, nextUrl, target;\n target = angular.element(event.currentTarget);\n nextUrl = target.prop(\"href\");\n currentUrl = $location.absUrl();\n if (nextUrl === currentUrl) {\n hideMenu();\n return;\n }\n $(document.body).addClass('loading-project');\n tgLoader.preventLoading();\n return loadingStart = new Date().getTime();\n });\n $el.on(\"click\", \".create-project-button .button\", function(event) {\n event.preventDefault();\n return $ctrl.newProject();\n });\n $el.on(\"keyup\", \".search-project\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n return $ctrl.filterProjects(target.val());\n });\n $scope.$on(\"projects:filtered\", function() {\n return renderProjects($scope.filteredProjects);\n });\n return $scope.$watch(\"projects\", function(projects) {\n if (projects != null) {\n return render(projects);\n }\n });\n };\n return {\n require: [\"tgProjectsNav\"],\n controller: ProjectsNavigationController,\n link: link\n };\n };\n\n module.directive(\"tgProjectsNav\", [\"$rootScope\", \"animationFrame\", \"$timeout\", \"tgLoader\", \"$tgLocation\", \"$compile\", ProjectsNavigationDirective]);\n\n ProjectMenuDirective = function($log, $compile, $auth, $rootscope, $tgAuth, $location, $navUrls, $config) {\n var getSectionName, link, mainTemplate, menuEntriesTemplate, renderMainMenu, renderMenuEntries, videoConferenceUrl;\n menuEntriesTemplate = _.template(\"
    \\n \\n
    \\n
    \\n \\n \\n \\\" alt=\\\"<%- user.full_name_display %>\\\" />\\n \\n
    \\n
    \\n
    \");\n mainTemplate = _.template(\"
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n taiga[beta]\\n
    \\n
    \");\n getSectionName = function($el, sectionName, project) {\n var oldSectionName, _ref;\n oldSectionName = (_ref = $el.find(\"a.active\").parent().attr(\"id\")) != null ? _ref.replace(\"nav-\", \"\") : void 0;\n if (sectionName === \"backlog-kanban\") {\n if (oldSectionName === \"backlog\" || oldSectionName === \"kanban\") {\n sectionName = oldSectionName;\n } else if (project.is_backlog_activated && !project.is_kanban_activated) {\n sectionName = \"backlog\";\n } else if (!project.is_backlog_activated && project.is_kanban_activated) {\n sectionName = \"kanban\";\n }\n }\n return sectionName;\n };\n renderMainMenu = function($el) {\n var html;\n html = mainTemplate({});\n return $el.html(html);\n };\n renderMenuEntries = function($el, targetScope, project) {\n var container, ctx, dom, sectionName;\n if (project == null) {\n project = {};\n }\n container = $el.find(\".menu-container\");\n sectionName = getSectionName($el, targetScope.section, project);\n ctx = {\n user: $auth.getUser(),\n project: project,\n feedbackEnabled: $config.get(\"feedbackEnabled\")\n };\n dom = $compile(menuEntriesTemplate(ctx))(targetScope);\n dom.find(\"a.active\").removeClass(\"active\");\n dom.find(\"#nav-\" + sectionName + \" > a\").addClass(\"active\");\n return container.replaceWith(dom);\n };\n videoConferenceUrl = function(project) {\n var baseUrl, url;\n if (project.videoconferences === \"appear-in\") {\n baseUrl = \"https://appear.in/\";\n } else if (project.videoconferences === \"talky\") {\n baseUrl = \"https://talky.io/\";\n } else {\n return \"\";\n }\n if (project.videoconferences_salt) {\n url = \"\" + project.slug + \"-\" + project.videoconferences_salt;\n } else {\n url = \"\" + project.slug;\n }\n return baseUrl + url;\n };\n link = function($scope, $el, $attrs, $ctrl) {\n var project;\n renderMainMenu($el);\n project = null;\n $el.on(\"click\", \".logo\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return $rootscope.$broadcast(\"nav:projects-list:open\");\n });\n $el.on(\"click\", \".user-settings .avatar\", function(event) {\n event.preventDefault();\n return $el.find(\".user-settings .popover\").popover().open();\n });\n $el.on(\"click\", \".logout\", function(event) {\n event.preventDefault();\n $auth.logout();\n return $scope.$apply(function() {\n return $location.path($navUrls.resolve(\"login\"));\n });\n });\n $el.on(\"click\", \"#nav-search > a\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"search-box:show\", project);\n });\n $el.on(\"click\", \".feedback\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"feedback:show\");\n });\n $scope.$on(\"projects:loaded\", function(listener) {\n $el.addClass(\"hidden\");\n return listener.stopPropagation();\n });\n return $scope.$on(\"project:loaded\", function(ctx, newProject) {\n project = newProject;\n if ($el.hasClass(\"hidden\")) {\n $el.removeClass(\"hidden\");\n }\n project.videoconferenceUrl = videoConferenceUrl(project);\n return renderMenuEntries($el, ctx.targetScope, project);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectMenu\", [\"$log\", \"$compile\", \"$tgAuth\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfig\", ProjectMenuDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/projects.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaProject\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/related-tasks.coffee\n */\n\n(function() {\n var RelatedTaskAssignedToInlineEditionDirective, RelatedTaskCreateButtonDirective, RelatedTaskCreateFormDirective, RelatedTaskRowDirective, RelatedTasksDirective, debounce, module, taiga, trim;\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaRelatedTasks\", []);\n\n RelatedTaskRowDirective = function($repo, $compile, $confirm, $rootscope, $loading) {\n var link, templateEdit, templateView;\n templateView = _.template(\"
    \\n
    \\n \\n <%- task.subject %>\\\" class=\\\"clickable\\\">\\n #<%- task.ref %>\\n <%- task.subject %>\\n \\n
    \\n <% if(perms.modify_task) { %>\\n \\n <% } %>\\n <% if(perms.delete_task) { %>\\n \\n <% } %>\\n
    \\n
    \\n
    \\n\\n
    \\n
    editable<% } %>\\\">\\n
    \\n <% if(perms.modify_task) { %>\\n \\n <% } %>\\n
    \\n
    \");\n templateEdit = _.template(\"
    \\n
    \\n \\\" placeholder=\\\"Type the task subject\\\" />\\n
    \\n \\n \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n
    \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var renderEdit, renderView, saveTask;\n saveTask = debounce(2000, function(task) {\n var promise;\n task.subject = $el.find('input').val();\n $loading.start($el.find('.task-name'));\n promise = $repo.save(task);\n promise.then((function(_this) {\n return function() {\n $loading.finish($el.find('.task-name'));\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"related-tasks:update\");\n };\n })(this));\n promise.then(null, (function(_this) {\n return function() {\n $loading.finish($el.find('.task-name'));\n $el.find('input').val(task.subject);\n return $confirm.notify(\"error\");\n };\n })(this));\n return promise;\n });\n renderEdit = function(task) {\n $el.html($compile(templateEdit({\n task: task\n }))($scope));\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return saveTask($model.$modelValue).then(function() {\n return renderView($model.$modelValue);\n });\n } else if (event.keyCode === 27) {\n return renderView($model.$modelValue);\n }\n });\n $el.on(\"click\", \".icon-floppy\", function(event) {\n return saveTask($model.$modelValue).then(function() {\n return renderView($model.$modelValue);\n });\n });\n return $el.on(\"click\", \".cancel-edit\", function(event) {\n return renderView($model.$modelValue);\n });\n };\n renderView = function(task) {\n var perms;\n $el.off();\n perms = {\n modify_task: $scope.project.my_permissions.indexOf(\"modify_task\") !== -1,\n delete_task: $scope.project.my_permissions.indexOf(\"delete_task\") !== -1\n };\n $el.html($compile(templateView({\n task: task,\n perms: perms\n }))($scope));\n $el.on(\"click\", \".icon-edit\", function() {\n renderEdit($model.$modelValue);\n return $el.find('input').focus().select();\n });\n return $el.on(\"click\", \".delete-task\", function(event) {\n var message, title;\n task = $model.$modelValue;\n title = \"Delete Task\";\n message = task.subject;\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var promise;\n promise = $repo.remove(task);\n promise.then(function() {\n finish();\n $confirm.notify(\"success\");\n return $scope.$emit(\"related-tasks:delete\");\n });\n return promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n });\n });\n };\n $scope.$watch($attrs.ngModel, function(val) {\n if (!val) {\n return;\n }\n return renderView(val);\n });\n $scope.$on(\"related-tasks:assigned-to-changed\", function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n $scope.$on(\"related-tasks:status-changed\", function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgRelatedTaskRow\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$rootScope\", \"$tgLoading\", \"$tgAnalytics\", RelatedTaskRowDirective]);\n\n RelatedTaskCreateFormDirective = function($repo, $compile, $confirm, $tgmodel, $loading, $analytics) {\n var link, newTask, template;\n template = _.template(\"
    \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n
    \\n
    \");\n newTask = {\n subject: \"\",\n assigned_to: null\n };\n link = function($scope, $el, $attrs) {\n var createTask, render;\n createTask = debounce(2000, function(task) {\n var promise;\n task.subject = $el.find('input').val();\n task.assigned_to = $scope.newTask.assigned_to;\n task.status = $scope.newTask.status;\n $scope.newTask.status = $scope.project.default_task_status;\n $scope.newTask.assigned_to = null;\n $loading.start($el.find('.task-name'));\n promise = $repo.create(\"tasks\", task);\n promise.then(function() {\n $analytics.trackEvent(\"task\", \"create\", \"create task on userstory\", 1);\n $loading.finish($el.find('.task-name'));\n $scope.$emit(\"related-tasks:add\");\n return $confirm.notify(\"success\");\n });\n promise.then(null, function() {\n $el.find('input').val(task.subject);\n $loading.finish($el.find('.task-name'));\n return $confirm.notify(\"error\");\n });\n return promise;\n });\n render = function() {\n $el.off();\n $el.html($compile(template())($scope));\n $el.find('input').focus().select();\n $el.addClass('active');\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return createTask(newTask).then(function() {\n return render();\n });\n } else if (event.keyCode === 27) {\n return $el.html(\"\");\n }\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n return $el.html(\"\");\n });\n return $el.on(\"click\", \".icon-floppy\", function(event) {\n return createTask(newTask).then(function() {\n return $el.html(\"\");\n });\n });\n };\n taiga.bindOnce($scope, \"us\", function(val) {\n newTask[\"status\"] = $scope.project.default_task_status;\n newTask[\"project\"] = $scope.project.id;\n newTask[\"user_story\"] = $scope.us.id;\n $scope.newTask = $tgmodel.make_model(\"tasks\", newTask);\n return $el.html(\"\");\n });\n $scope.$on(\"related-tasks:show-form\", function() {\n return render();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskCreateForm\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$tgModel\", \"$tgLoading\", \"$tgAnalytics\", RelatedTaskCreateFormDirective]);\n\n RelatedTaskCreateButtonDirective = function($repo, $compile, $confirm, $tgmodel) {\n var link, template;\n template = _.template(\"\");\n link = function($scope, $el, $attrs) {\n $scope.$watch(\"project\", function(val) {\n if (!val) {\n return;\n }\n $el.off();\n if ($scope.project.my_permissions.indexOf(\"add_task\") !== -1) {\n $el.html(template());\n } else {\n $el.html(\"\");\n }\n return $el.on(\"click\", \".icon\", function(event) {\n return $scope.$emit(\"related-tasks:add-new-clicked\");\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskCreateButton\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$tgModel\", RelatedTaskCreateButtonDirective]);\n\n RelatedTasksDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var loadTasks;\n loadTasks = function() {\n return $rs.tasks.list($scope.projectId, null, $scope.usId).then((function(_this) {\n return function(tasks) {\n $scope.tasks = tasks;\n return tasks;\n };\n })(this));\n };\n $scope.$on(\"related-tasks:add\", function() {\n return loadTasks().then(function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n });\n $scope.$on(\"related-tasks:delete\", function() {\n return loadTasks().then(function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n });\n $scope.$on(\"related-tasks:add-new-clicked\", function() {\n return $scope.$broadcast(\"related-tasks:show-form\");\n });\n taiga.bindOnce($scope, \"us\", function(val) {\n return loadTasks();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTasks\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", RelatedTasksDirective]);\n\n RelatedTaskAssignedToInlineEditionDirective = function($repo, $rootscope, popoverService) {\n var link, template;\n template = _.template(\"\\\" alt=\\\"<%- name %>\\\"/>\\n
    <%- name %>
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, autoSave, notAutoSave, task, updateRelatedTask;\n updateRelatedTask = function(task) {\n var ctx, member;\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = $scope.usersById[task.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name_display;\n }\n $el.find(\".avatar\").html(template(ctx));\n return $el.find(\".task-assignedto\").attr('title', ctx.name);\n };\n $ctrl = $el.controller();\n task = $scope.$eval($attrs.tgRelatedTaskAssignedToInlineEdition);\n notAutoSave = $scope.$eval($attrs.notAutoSave);\n autoSave = !notAutoSave;\n updateRelatedTask(task);\n $el.on(\"click\", \".task-assignedto\", function(event) {\n return $rootscope.$broadcast(\"assigned-to:add\", task);\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_task\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"assigned-to:added\", debounce(2000, (function(_this) {\n return function(ctx, userId, updatedRelatedTask) {\n if (updatedRelatedTask.id === task.id) {\n updatedRelatedTask.assigned_to = userId;\n if (autoSave) {\n $repo.save(updatedRelatedTask).then(function() {\n return $scope.$emit(\"related-tasks:assigned-to-changed\");\n });\n }\n return updateRelatedTask(updatedRelatedTask);\n }\n };\n })(this)));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskAssignedToInlineEdition\", [\"$tgRepo\", \"$rootScope\", RelatedTaskAssignedToInlineEditionDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources.coffee\n */\n\n(function() {\n var ResourcesService, initResources, initUrls, module, taiga, urls,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n ResourcesService = (function(_super) {\n __extends(ResourcesService, _super);\n\n function ResourcesService() {\n return ResourcesService.__super__.constructor.apply(this, arguments);\n }\n\n return ResourcesService;\n\n })(taiga.Service);\n\n urls = {\n \"auth\": \"/auth\",\n \"auth-register\": \"/auth/register\",\n \"invitations\": \"/invitations\",\n \"permissions\": \"/permissions\",\n \"roles\": \"/roles\",\n \"projects\": \"/projects\",\n \"memberships\": \"/memberships\",\n \"notify-policies\": \"/notify-policies\",\n \"bulk-create-memberships\": \"/memberships/bulk_create\",\n \"milestones\": \"/milestones\",\n \"userstories\": \"/userstories\",\n \"bulk-create-us\": \"/userstories/bulk_create\",\n \"bulk-update-us-backlog-order\": \"/userstories/bulk_update_backlog_order\",\n \"bulk-update-us-sprint-order\": \"/userstories/bulk_update_sprint_order\",\n \"bulk-update-us-kanban-order\": \"/userstories/bulk_update_kanban_order\",\n \"userstories-restore\": \"/userstories/%s/restore\",\n \"tasks\": \"/tasks\",\n \"bulk-create-tasks\": \"/tasks/bulk_create\",\n \"bulk-update-task-taskboard-order\": \"/tasks/bulk_update_taskboard_order\",\n \"tasks-restore\": \"/tasks/%s/restore\",\n \"issues\": \"/issues\",\n \"bulk-create-issues\": \"/issues/bulk_create\",\n \"issues-restore\": \"/issues/%s/restore\",\n \"wiki\": \"/wiki\",\n \"wiki-restore\": \"/wiki/%s/restore\",\n \"wiki-links\": \"/wiki-links\",\n \"choices/userstory-statuses\": \"/userstory-statuses\",\n \"choices/userstory-statuses/bulk-update-order\": \"/userstory-statuses/bulk_update_order\",\n \"choices/points\": \"/points\",\n \"choices/points/bulk-update-order\": \"/points/bulk_update_order\",\n \"choices/task-statuses\": \"/task-statuses\",\n \"choices/task-statuses/bulk-update-order\": \"/task-statuses/bulk_update_order\",\n \"choices/issue-statuses\": \"/issue-statuses\",\n \"choices/issue-statuses/bulk-update-order\": \"/issue-statuses/bulk_update_order\",\n \"choices/issue-types\": \"/issue-types\",\n \"choices/issue-types/bulk-update-order\": \"/issue-types/bulk_update_order\",\n \"choices/priorities\": \"/priorities\",\n \"choices/priorities/bulk-update-order\": \"/priorities/bulk_update_order\",\n \"choices/severities\": \"/severities\",\n \"choices/severities/bulk-update-order\": \"/severities/bulk_update_order\",\n \"search\": \"/search\",\n \"sites\": \"/sites\",\n \"project-templates\": \"/project-templates\",\n \"site-members\": \"/site-members\",\n \"site-projects\": \"/site-projects\",\n \"users\": \"/users\",\n \"users-password-recovery\": \"/users/password_recovery\",\n \"users-change-password-from-recovery\": \"/users/change_password_from_recovery\",\n \"users-change-password\": \"/users/change_password\",\n \"users-change-email\": \"/users/change_email\",\n \"users-cancel-account\": \"/users/cancel\",\n \"user-storage\": \"/user-storage\",\n \"resolver\": \"/resolver\",\n \"userstory-statuses\": \"/userstory-statuses\",\n \"points\": \"/points\",\n \"task-statuses\": \"/task-statuses\",\n \"issue-statuses\": \"/issue-statuses\",\n \"issue-types\": \"/issue-types\",\n \"priorities\": \"/priorities\",\n \"severities\": \"/severities\",\n \"project-modules\": \"/projects/%s/modules\",\n \"history/us\": \"/history/userstory\",\n \"history/issue\": \"/history/issue\",\n \"history/task\": \"/history/task\",\n \"history/wiki\": \"/history/wiki\",\n \"attachments/us\": \"/userstories/attachments\",\n \"attachments/issue\": \"/issues/attachments\",\n \"attachments/task\": \"/tasks/attachments\",\n \"attachments/wiki_page\": \"/wiki/attachments\",\n \"feedback\": \"/feedback\"\n };\n\n initUrls = function($log, $urls) {\n $log.debug(\"Initialize api urls\");\n return $urls.update(urls);\n };\n\n initResources = function($log, $rs) {\n var provider, providers, _i, _len, _results;\n $log.debug(\"Initialize resources\");\n providers = _.toArray(arguments).slice(2);\n _results = [];\n for (_i = 0, _len = providers.length; _i < _len; _i++) {\n provider = providers[_i];\n _results.push(provider($rs));\n }\n return _results;\n };\n\n module = angular.module(\"taigaResources\", [\"taigaBase\"]);\n\n module.service(\"$tgResources\", ResourcesService);\n\n module.run([\"$log\", \"$tgUrls\", initUrls]);\n\n module.run([\"$log\", \"$tgResources\", \"$tgProjectsResourcesProvider\", \"$tgMembershipsResourcesProvider\", \"$tgNotifyPoliciesResourcesProvider\", \"$tgInvitationsResourcesProvider\", \"$tgRolesResourcesProvider\", \"$tgUserSettingsResourcesProvider\", \"$tgSprintsResourcesProvider\", \"$tgUserstoriesResourcesProvider\", \"$tgTasksResourcesProvider\", \"$tgIssuesResourcesProvider\", \"$tgWikiResourcesProvider\", \"$tgSearchResourcesProvider\", \"$tgAttachmentsResourcesProvider\", \"$tgMdRenderResourcesProvider\", \"$tgHistoryResourcesProvider\", \"$tgKanbanResourcesProvider\", \"$tgModulesResourcesProvider\", initResources]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/search.coffee\n */\n\n(function() {\n var SearchBoxDirective, SearchController, SearchDirective, bindOnce, debounce, debounceLeading, groupBy, mixOf, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n mixOf = this.taiga.mixOf;\n\n debounceLeading = this.taiga.debounceLeading;\n\n trim = this.taiga.trim;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaSearch\", []);\n\n SearchController = (function(_super) {\n __extends(SearchController, _super);\n\n SearchController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"tgLoader\"];\n\n function SearchController(scope, repo, rs, params, q, location, appTitle, navUrls, tgLoader) {\n var loadSearchData, promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.tgLoader = tgLoader;\n this.scope.sectionName = \"Search\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Search\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.searchTerm = \"\";\n loadSearchData = debounceLeading(100, (function(_this) {\n return function(t) {\n return _this.loadSearchData(t);\n };\n })(this));\n this.scope.$watch(\"searchTerm\", (function(_this) {\n return function(term) {\n if (!term) {\n return _this.tgLoader.pageLoaded();\n } else {\n return loadSearchData(term);\n }\n };\n })(this));\n }\n\n SearchController.prototype.loadFilters = function() {\n var defered;\n defered = this.q.defer();\n defered.resolve();\n return defered.promise;\n };\n\n SearchController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issueStatusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.taskStatusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n return project;\n };\n })(this));\n };\n\n SearchController.prototype.loadSearchData = function(term) {\n var promise;\n promise = this.rs.search[\"do\"](this.scope.projectId, term).then((function(_this) {\n return function(data) {\n _this.scope.searchResults = data;\n return data;\n };\n })(this));\n promise[\"finally\"]((function(_this) {\n return function() {\n return _this.tgLoader.pageLoaded();\n };\n })(this));\n return promise;\n };\n\n SearchController.prototype.loadInitialData = function() {\n return this.loadProject().then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n return _this.fillUsersAndRoles(project.users, project.roles);\n };\n })(this));\n };\n\n return SearchController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"SearchController\", SearchController);\n\n SearchBoxDirective = function($lightboxService, $navurls, $location, $route) {\n var link;\n link = function($scope, $el, $attrs) {\n var project, submit;\n project = null;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, text, url;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n text = $el.find(\"#search-text\").val();\n url = $navurls.resolve(\"project-search\", {\n project: project.slug\n });\n $lightboxService.close($el);\n return $scope.$apply(function() {\n $location.path(url);\n $location.search(\"text\", text).path(url);\n return $route.reload();\n });\n };\n })(this));\n $scope.$on(\"search-box:show\", function(ctx, newProject) {\n project = newProject;\n $lightboxService.open($el);\n return $el.find(\"#search-text\").val(\"\");\n });\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSearchBox\", [\"lightboxService\", \"$tgNavUrls\", \"$tgLocation\", \"$route\", SearchBoxDirective]);\n\n SearchDirective = function($log, $compile, $templatecache, $routeparams, $location) {\n var link, linkTable;\n linkTable = function($scope, $el, $attrs, $ctrl) {\n var getActiveSection, lastSeatchResults, markSectionTabActive, renderFilterTabs, renderTableContent, tabsDom, templates;\n tabsDom = $el.find(\"section.search-filter\");\n lastSeatchResults = null;\n getActiveSection = function(data) {\n var maxVal, name, selectedSectionData, selectedSectionName, value;\n maxVal = 0;\n selectedSectionName = null;\n selectedSectionData = null;\n for (name in data) {\n value = data[name];\n if (name === \"count\") {\n continue;\n }\n if (value.length > maxVal) {\n maxVal = value.length;\n selectedSectionName = name;\n selectedSectionData = value;\n }\n }\n if (maxVal === 0) {\n return {\n name: \"userstories\",\n value: []\n };\n }\n return {\n name: selectedSectionName,\n value: selectedSectionData\n };\n };\n renderFilterTabs = function(data) {\n var name, value, _results;\n _results = [];\n for (name in data) {\n value = data[name];\n if (name === \"count\") {\n continue;\n }\n _results.push(tabsDom.find(\"li.\" + name + \" .num\").html(value.length));\n }\n return _results;\n };\n markSectionTabActive = function(section) {\n tabsDom.find(\"a.active\").removeClass(\"active\");\n return tabsDom.find(\"li.\" + section.name + \" a\").addClass(\"active\");\n };\n templates = {\n issues: $templatecache.get(\"search-issues\"),\n tasks: $templatecache.get(\"search-tasks\"),\n userstories: $templatecache.get(\"search-userstories\"),\n wikipages: $templatecache.get(\"search-wikipages\")\n };\n renderTableContent = function(section) {\n var element, oldElements, oldScope, scope, template;\n oldElements = $el.find(\".search-result-table\").children();\n oldScope = oldElements.scope();\n if (oldScope) {\n oldScope.$destroy();\n oldElements.remove();\n }\n scope = $scope.$new();\n scope[section.name] = section.value;\n template = angular.element.parseHTML(trim(templates[section.name]));\n element = $compile(template)(scope);\n return $el.find(\".search-result-table\").html(element);\n };\n $scope.$watch(\"searchResults\", function(data) {\n var activeSection;\n lastSeatchResults = data;\n activeSection = getActiveSection(data);\n renderFilterTabs(data);\n renderTableContent(activeSection);\n return markSectionTabActive(activeSection);\n });\n $scope.$watch(\"searchTerm\", function(searchTerm) {\n if (searchTerm) {\n return $location.search(\"text\", searchTerm);\n }\n });\n return $el.on(\"click\", \".search-filter li > a\", function(event) {\n var section, sectionData, sectionName, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n sectionName = target.parent().data(\"name\");\n sectionData = lastSeatchResults[sectionName];\n section = {\n name: sectionName,\n value: sectionData\n };\n return $scope.$apply(function() {\n renderTableContent(section);\n return markSectionTabActive(section);\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, searchText;\n $ctrl = $el.controller();\n linkTable($scope, $el, $attrs, $ctrl);\n searchText = $routeparams.text;\n return $scope.$watch(\"projectId\", function(projectId) {\n if (projectId != null) {\n return $scope.searchTerm = searchText;\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSearch\", [\"$log\", \"$compile\", \"$templateCache\", \"$routeParams\", \"$tgLocation\", SearchDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTaskboard\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/tasks.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTasks\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/team.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTeam\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaUserSettings\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/userstories.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaUserStories\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaWiki\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/analytics.coffee\n */\n\n(function() {\n var AnalyticsService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n AnalyticsService = (function(_super) {\n __extends(AnalyticsService, _super);\n\n AnalyticsService.$inject = [\"$rootScope\", \"$log\", \"$tgConfig\", \"$window\", \"$document\", \"$location\"];\n\n function AnalyticsService(rootscope, log, config, win, doc, location) {\n var conf;\n this.rootscope = rootscope;\n this.log = log;\n this.config = config;\n this.win = win;\n this.doc = doc;\n this.location = location;\n this.initialized = false;\n conf = this.config.get(\"analytics\", {});\n this.accountId = conf.accountId;\n this.pageEvent = conf.pageEvent || \"$routeChangeSuccess\";\n this.trackRoutes = conf.trackRoutes || true;\n this.ignoreFirstPageLoad = conf.ignoreFirstPageLoad || false;\n }\n\n AnalyticsService.prototype.initialize = function() {\n if (!this.accountId) {\n this.log.debug(\"Analytics: no acount id provided. Disabling.\");\n return;\n }\n this.injectAnalytics();\n this.win.ga(\"create\", this.accountId, \"auto\");\n this.win.ga(\"require\", \"displayfeatures\");\n if (this.trackRoutes && (!this.ignoreFirstPageLoad)) {\n this.win.ga(\"send\", \"pageview\", this.getUrl());\n }\n if (this.trackRoutes) {\n this.rootscope.$on(this.pageEvent, (function(_this) {\n return function() {\n return _this.trackPage(_this.getUrl(), \"Taiga\");\n };\n })(this));\n }\n return this.initialized = true;\n };\n\n AnalyticsService.prototype.getUrl = function() {\n return this.location.path();\n };\n\n AnalyticsService.prototype.injectAnalytics = function() {\n var fn;\n fn = (function(i,s,o,g,r,a,m){i[\"GoogleAnalyticsObject\"]=r;i[r]=i[r]||function(){\n (i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o),\n m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m);});\n return fn(window, document, \"script\", \"//www.google-analytics.com/analytics.js\", \"ga\");\n };\n\n AnalyticsService.prototype.trackPage = function(url, title) {\n if (!this.initialized) {\n return;\n }\n if (!this.win.ga) {\n return;\n }\n title = title || this.doc[0].title;\n return this.win.ga(\"send\", \"pageview\", {\n \"page\": url,\n \"title\": title\n });\n };\n\n AnalyticsService.prototype.trackEvent = function(category, action, label, value) {\n if (!this.initialized) {\n return;\n }\n if (!this.win.ga) {\n return;\n }\n return this.win.ga(\"send\", \"event\", category, action, label, value);\n };\n\n return AnalyticsService;\n\n })(taiga.Service);\n\n module.service(\"$tgAnalytics\", AnalyticsService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var AttachmentDirective, AttachmentsController, AttachmentsDirective, bindMethods, bindOnce, module, sizeFormat, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n bindOnce = this.taiga.bindOnce;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaCommon\");\n\n AttachmentsController = (function(_super) {\n __extends(AttachmentsController, _super);\n\n AttachmentsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$q\"];\n\n function AttachmentsController(scope, rootscope, repo, rs, confirm, q) {\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.rs = rs;\n this.confirm = confirm;\n this.q = q;\n bindMethods(this);\n this.type = null;\n this.objectId = null;\n this.projectId = null;\n this.uploadingAttachments = [];\n this.attachments = [];\n this.attachmentsCount = 0;\n this.deprecatedAttachmentsCount = 0;\n this.showDeprecated = false;\n }\n\n AttachmentsController.prototype.initialize = function(type, objectId) {\n this.type = type;\n this.objectId = objectId;\n return this.projectId = this.scope.projectId;\n };\n\n AttachmentsController.prototype.loadAttachments = function() {\n var urlname;\n if (!this.objectId) {\n return this.attachments;\n }\n urlname = \"attachments/\" + this.type;\n return this.rs.attachments.list(urlname, this.objectId, this.projectId).then((function(_this) {\n return function(attachments) {\n _this.attachments = _.sortBy(attachments, \"order\");\n _this.updateCounters();\n return attachments;\n };\n })(this));\n };\n\n AttachmentsController.prototype.updateCounters = function() {\n this.attachmentsCount = this.attachments.length;\n return this.deprecatedAttachmentsCount = _.filter(this.attachments, {\n is_deprecated: true\n }).length;\n };\n\n AttachmentsController.prototype._createAttachment = function(attachment) {\n var promise, urlName;\n urlName = \"attachments/\" + this.type;\n promise = this.rs.attachments.create(urlName, this.projectId, this.objectId, attachment);\n promise = promise.then((function(_this) {\n return function(data) {\n var index;\n data.isCreatedRightNow = true;\n index = _this.uploadingAttachments.indexOf(attachment);\n _this.uploadingAttachments.splice(index, 1);\n _this.attachments.push(data);\n return _this.rootscope.$broadcast(\"attachment:create\");\n };\n })(this));\n promise = promise.then(null, (function(_this) {\n return function(data) {\n var index;\n if (data.status === 413) {\n _this.scope.$emit(\"attachments:size-error\");\n }\n index = _this.uploadingAttachments.indexOf(attachment);\n _this.uploadingAttachments.splice(index, 1);\n _this.confirm.notify(\"error\", \"We have not been able to upload '\" + attachment.name + \"'. \" + data.data._error_message);\n return _this.q.reject(data);\n };\n })(this));\n return promise;\n };\n\n AttachmentsController.prototype.createAttachments = function(attachments) {\n var promises;\n promises = _.map(attachments, (function(_this) {\n return function(x) {\n return _this._createAttachment(x);\n };\n })(this));\n return this.q.all(promises).then((function(_this) {\n return function() {\n return _this.updateCounters();\n };\n })(this));\n };\n\n AttachmentsController.prototype.addUploadingAttachments = function(attachments) {\n return this.uploadingAttachments = _.union(this.uploadingAttachments, attachments);\n };\n\n AttachmentsController.prototype.reorderAttachment = function(attachment, newIndex) {\n var oldIndex;\n oldIndex = this.attachments.indexOf(attachment);\n if (oldIndex === newIndex) {\n return;\n }\n this.attachments.splice(oldIndex, 1);\n this.attachments.splice(newIndex, 0, attachment);\n return _.each(this.attachments, function(x, i) {\n return x.order = i + 1;\n });\n };\n\n AttachmentsController.prototype.updateAttachment = function(attachment) {\n var onError, onSuccess;\n onSuccess = (function(_this) {\n return function() {\n _this.updateCounters();\n return _this.rootscope.$broadcast(\"attachment:edit\");\n };\n })(this);\n onError = (function(_this) {\n return function(response) {\n if (response.status === 413) {\n $scope.$emit(\"attachments:size-error\");\n }\n _this.confirm.notify(\"error\");\n return _this.q.reject();\n };\n })(this);\n return this.repo.save(attachment).then(onSuccess, onError);\n };\n\n AttachmentsController.prototype.saveAttachments = function() {\n return this.repo.saveAll(this.attachments).then(null, (function(_this) {\n return function() {\n var item, _i, _len, _ref;\n _ref = _this.attachments;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n item = _ref[_i];\n item.revert();\n }\n return _this.attachments = _.sorBy(_this.attachments, \"order\");\n };\n })(this));\n };\n\n AttachmentsController.prototype.removeAttachment = function(attachment) {\n var message, title;\n title = \"Delete attachment\";\n message = \"the attachment '\" + attachment.name + \"'\";\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n var index;\n finish();\n index = _this.attachments.indexOf(attachment);\n _this.attachments.splice(index, 1);\n _this.updateCounters();\n return _this.rootscope.$broadcast(\"attachment:delete\");\n };\n onError = function() {\n finish(false);\n _this.confirm.notify(\"error\", null, \"We have not been able to delete \" + message + \".\");\n return _this.q.reject();\n };\n return _this.repo.remove(attachment).then(onSuccess, onError);\n };\n })(this));\n };\n\n AttachmentsController.prototype.filterAttachments = function(item) {\n if (this.showDeprecated) {\n return true;\n }\n return !item.is_deprecated;\n };\n\n return AttachmentsController;\n\n })(taiga.Controller);\n\n AttachmentsDirective = function($config, $confirm) {\n var link, template, templateFn;\n template = _.template(\"
    \\n
    \\n

    \\n \\n attachments\\n

    \\n
    \\\" class=\\\"add-attach\\\"\\n title=\\\"Add new attachment. <%- maxFileSizeMsg %>\\\">\\n <% if (maxFileSize){ %>\\n [Max. size: <%- maxFileSize %>]\\n <% }; %>\\n \\n \\n
    \\n
    \\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $ctrls) {\n var $ctrl, $model, showSizeInfo, tdom;\n $ctrl = $ctrls[0];\n $model = $ctrls[1];\n bindOnce($scope, $attrs.ngModel, function(value) {\n $ctrl.initialize($attrs.type, value.id);\n return $ctrl.loadAttachments();\n });\n tdom = $el.find(\"div.attachment-body.sortable\");\n tdom.sortable({\n items: \"div.single-attachment\",\n handle: \"a.settings.icon.icon-drag-v\",\n containment: \".attachments\",\n dropOnEmpty: true,\n scroll: false,\n tolerance: \"pointer\",\n placeholder: \"sortable-placeholder single-attachment\"\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var attachment, newIndex;\n attachment = ui.item.scope().attach;\n newIndex = ui.item.index();\n $ctrl.reorderAttachment(attachment, newIndex);\n return $ctrl.saveAttachments();\n });\n showSizeInfo = function() {\n return $el.find(\".size-info\").removeClass(\"hidden\");\n };\n $scope.$on(\"attachments:size-error\", function() {\n return showSizeInfo();\n });\n $el.on(\"change\", \".attachments-header input\", function(event) {\n var files;\n files = _.toArray(event.target.files);\n if (files.length < 1) {\n return;\n }\n return $scope.$apply(function() {\n $ctrl.addUploadingAttachments(files);\n return $ctrl.createAttachments(files);\n });\n });\n $el.on(\"click\", \".more-attachments\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n $scope.$apply(function() {\n return $ctrl.showDeprecated = !$ctrl.showDeprecated;\n });\n target.find(\"span.text\").addClass(\"hidden\");\n if ($ctrl.showDeprecated) {\n target.find(\"span[data-type=hide]\").removeClass(\"hidden\");\n return target.find(\"more-attachments-num\").addClass(\"hidden\");\n } else {\n target.find(\"span[data-type=show]\").removeClass(\"hidden\");\n return target.find(\"more-attachments-num\").removeClass(\"hidden\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n templateFn = function($el, $attrs) {\n var ctx, maxFileSize, maxFileSizeMsg;\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize) {\n maxFileSize = sizeFormat(maxFileSize);\n }\n maxFileSizeMsg = maxFileSize ? \"Maximum upload size is \" + maxFileSize : \"\";\n ctx = {\n type: $attrs.type,\n maxFileSize: maxFileSize,\n maxFileSizeMsg: maxFileSizeMsg\n };\n return template(ctx);\n };\n return {\n require: [\"tgAttachments\", \"ngModel\"],\n controller: AttachmentsController,\n controllerAs: \"ctrl\",\n restrict: \"AE\",\n scope: true,\n link: link,\n template: templateFn\n };\n };\n\n module.directive(\"tgAttachments\", [\"$tgConfig\", \"$tgConfirm\", AttachmentsDirective]);\n\n AttachmentDirective = function() {\n var link, template, templateEdit;\n template = _.template(\"\\n
    \\n <%- size %>\\n
    \\n
    \\n <% if (isDeprecated){ %> (deprecated) <% } %>\\n <%- description %>\\n
    \\n<% if (modifyPermission) {%>\\n
    \\n \\n \\n \\n
    \\n<% } %>\");\n templateEdit = _.template(\"\\n
    \\n <%- size %>\\n
    \\n
    \\n \\\"\\\"\\n placeholder=\\\"Type a short description\\\" />\\n
    \\n
    \\n -is-deprecated\\\"\\n <% if (isDeprecated){ %>checked<% } %> />\\n \\n
    \\n
    \\n \\n \\n
    \");\n link = function($scope, $el, $attrs, $ctrl) {\n var attachment, render, saveAttachment;\n render = function(attachment, edit) {\n var ctx, html, modifyPermission, permissions;\n if (edit == null) {\n edit = false;\n }\n permissions = $scope.project.my_permissions;\n modifyPermission = permissions.indexOf(\"modify_\" + $ctrl.type) > -1;\n ctx = {\n id: attachment.id,\n name: attachment.name,\n created_date: moment(attachment.created_date).format(\"DD MMM YYYY [at] hh:mm\"),\n url: attachment.url,\n size: sizeFormat(attachment.size),\n description: attachment.description,\n isDeprecated: attachment.is_deprecated,\n modifyPermission: modifyPermission\n };\n if (edit) {\n html = templateEdit(ctx);\n } else {\n html = template(ctx);\n }\n $el.html(html);\n if (attachment.is_deprecated) {\n return $el.addClass(\"deprecated\");\n }\n };\n saveAttachment = function() {\n attachment.description = $el.find(\"input[name='description']\").val();\n attachment.is_deprecated = $el.find(\"input[name='is-deprecated']\").prop(\"checked\");\n return $scope.$apply(function() {\n return $ctrl.updateAttachment(attachment).then(function() {\n return render(attachment, false);\n });\n });\n };\n $el.on(\"click\", \"a.editable-settings.icon-floppy\", function(event) {\n event.preventDefault();\n return saveAttachment();\n });\n $el.on(\"keyup\", \"input[name=description]\", function(event) {\n if (event.keyCode === 13) {\n return saveAttachment();\n } else if (event.keyCode === 27) {\n return render(attachment, false);\n }\n });\n $el.on(\"click\", \"a.editable-settings.icon-delete\", function(event) {\n event.preventDefault();\n return render(attachment, false);\n });\n $el.on(\"click\", \"a.settings.icon-edit\", function(event) {\n event.preventDefault();\n render(attachment, true);\n return $el.find(\"input[name='description']\").focus().select();\n });\n $el.on(\"click\", \"a.settings.icon-delete\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n return $ctrl.removeAttachment(attachment);\n });\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n attachment = $scope.$eval($attrs.tgAttachment);\n render(attachment, attachment.isCreatedRightNow);\n if (attachment.isCreatedRightNow) {\n return $el.find(\"input[name='description']\").focus().select();\n }\n };\n return {\n link: link,\n require: \"^tgAttachments\",\n restrict: \"AE\"\n };\n };\n\n module.directive(\"tgAttachment\", AttachmentDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/components.coffee\n */\n\n(function() {\n var AssignedToDirective, BlockButtonDirective, CreatedByDisplayDirective, DateRangeDirective, DateSelectorDirective, DeleteButtonDirective, EditableDescriptionDirective, EditableSubjectDirective, ListItemAssignedtoDirective, ListItemIssueStatusDirective, ListItemPriorityDirective, ListItemSeverityDirective, ListItemTaskStatusDirective, ListItemTypeDirective, ListItemUsStatusDirective, SprintProgressBarDirective, TgMainTitleDirective, TgProgressBarDirective, WatchersDirective, bindOnce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n DateRangeDirective = function() {\n var link, renderRange;\n renderRange = function($el, first, second) {\n var endDate, initDate;\n initDate = moment(first).format(\"DD MMM YYYY\");\n endDate = moment(second).format(\"DD MMM YYYY\");\n return $el.html(\"\" + initDate + \"-\" + endDate);\n };\n link = function($scope, $el, $attrs) {\n var first, second, _ref;\n _ref = $attrs.tgDateRange.split(\",\"), first = _ref[0], second = _ref[1];\n return bindOnce($scope, first, function(valFirst) {\n return bindOnce($scope, second, function(valSecond) {\n return renderRange($el, valFirst, valSecond);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgDateRange\", DateRangeDirective);\n\n DateSelectorDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var selectedDate;\n selectedDate = null;\n $el.picker = new Pikaday({\n field: $el[0],\n format: \"DD MMM YYYY\",\n onSelect: (function(_this) {\n return function(date) {\n return selectedDate = date;\n };\n })(this),\n onOpen: (function(_this) {\n return function() {\n if (selectedDate != null) {\n return $el.picker.setDate(selectedDate);\n }\n };\n })(this)\n });\n return $scope.$watch($attrs.ngModel, function(val) {\n if (val != null) {\n return $el.picker.setDate(val);\n }\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgDateSelector\", DateSelectorDirective);\n\n SprintProgressBarDirective = function() {\n var link, renderProgress;\n renderProgress = function($el, percentage, visual_percentage) {\n if ($el.hasClass(\".current-progress\")) {\n return $el.css(\"width\", \"\" + percentage + \"%\");\n } else {\n $el.find(\".current-progress\").css(\"width\", \"\" + visual_percentage + \"%\");\n return $el.find(\".number\").html(\"\" + percentage + \" %\");\n }\n };\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgSprintProgressbar, function(sprint) {\n var closedPoints, percentage, totalPoints, visual_percentage;\n closedPoints = sprint.closed_points;\n totalPoints = sprint.total_points;\n percentage = 0;\n if (totalPoints !== 0) {\n percentage = Math.round(100 * (closedPoints / totalPoints));\n }\n visual_percentage = 0;\n if (totalPoints !== 0) {\n visual_percentage = Math.round(98 * (closedPoints / totalPoints));\n }\n return renderProgress($el, percentage, visual_percentage);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSprintProgressbar\", SprintProgressBarDirective);\n\n CreatedByDisplayDirective = function() {\n var link, template;\n template = _.template(\"
    \\n \\\" alt=\\\"<%- owner.full_name_display %>\\\" />\\n
    \\n\\n
    \\n Created by <%- owner.full_name_display %>\\n <%- date %>\\n
    \");\n link = function($scope, $el, $attrs) {\n var render;\n render = function(model) {\n var html, owner, _ref;\n owner = ((_ref = $scope.usersById) != null ? _ref[model.owner] : void 0) || {\n full_name_display: \"external user\",\n photo: \"/images/unnamed.png\"\n };\n html = template({\n owner: owner,\n date: moment(model.created_date).format(\"DD MMM YYYY HH:mm\")\n });\n return $el.html(html);\n };\n bindOnce($scope, $attrs.ngModel, function(model) {\n if (model != null) {\n return render(model);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgCreatedByDisplay\", CreatedByDisplayDirective);\n\n WatchersDirective = function($rootscope, $confirm, $repo, $qqueue) {\n var link, template;\n template = _.template(\"<% if(isEditable){ %>\\n
    \\n watchers\\n \\n
    \\n<% } else if(watchers.length > 0){ %>\\n
    \\n watchers\\n
    \\n<% }; %>\\n\\n<% _.each(watchers, function(watcher) { %>\\n<% if(watcher) { %>\\n
    \\n
    \\n \\\">\\n \\\" alt=\\\"<%- watcher.full_name_display %>\\\">\\n \\n
    \\n
    \\n <%- watcher.full_name_display %>\\n\\n <% if(isEditable){ %>\\n \\\" href=\\\"\\\" title=\\\"delete-watcher\\\">\\n \\n <% }; %>\\n
    \\n
    \\n<% } %>\\n<% }); %>\");\n link = function($scope, $el, $attrs, $model) {\n var deleteWatcher, isEditable, renderWatchers, save;\n isEditable = function() {\n var _ref, _ref1;\n return ((_ref = $scope.project) != null ? (_ref1 = _ref.my_permissions) != null ? _ref1.indexOf($attrs.requiredPerm) : void 0 : void 0) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(watchers) {\n var item, promise;\n item = $model.$modelValue.clone();\n item.watchers = watchers;\n $model.$setViewValue(item);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n watchers = _.map(watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n renderWatchers(watchers);\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n return $model.$modelValue.revert();\n });\n };\n })(this));\n deleteWatcher = $qqueue.bindAdd((function(_this) {\n return function(watcherIds) {\n var item, promise;\n item = $model.$modelValue.clone();\n item.watchers = watcherIds;\n $model.$setViewValue(item);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n var watchers;\n $confirm.notify(\"success\");\n watchers = _.map(item.watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n renderWatchers(watchers);\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n item.revert();\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n renderWatchers = function(watchers) {\n var ctx, html;\n ctx = {\n watchers: watchers,\n isEditable: isEditable()\n };\n html = template(ctx);\n $el.html(html);\n if (isEditable() && watchers.length === 0) {\n $el.find(\".title\").text(\"Add watchers\");\n return $el.find(\".watchers-header\").addClass(\"no-watchers\");\n }\n };\n $el.on(\"click\", \".icon-delete\", function(event) {\n var message, target, title, watcherId;\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n watcherId = target.data(\"watcher-id\");\n title = \"Delete watcher\";\n message = $scope.usersById[watcherId].full_name_display;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var watcherIds;\n finish();\n watcherIds = _.clone($model.$modelValue.watchers, false);\n watcherIds = _.pull(watcherIds, watcherId);\n return deleteWatcher(watcherIds);\n };\n })(this));\n });\n $el.on(\"click\", \".add-watcher\", function(event) {\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"watcher:add\", $model.$modelValue);\n });\n });\n $scope.$on(\"watcher:added\", function(ctx, watcherId) {\n var watchers;\n watchers = _.clone($model.$modelValue.watchers, false);\n watchers.push(watcherId);\n watchers = _.uniq(watchers);\n return save(watchers);\n });\n $scope.$watch($attrs.ngModel, function(item) {\n var watchers;\n if (item == null) {\n return;\n }\n watchers = _.map(item.watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n return renderWatchers(watchers);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgWatchers\", [\"$rootScope\", \"$tgConfirm\", \"$tgRepo\", \"$tgQqueue\", WatchersDirective]);\n\n AssignedToDirective = function($rootscope, $confirm, $repo, $loading, $qqueue) {\n var link, template;\n template = _.template(\"<% if (assignedTo) { %>\\n
    \\n \\\" alt=\\\"<%- assignedTo.full_name_display %>\\\" />\\n
    \\n<% } %>\\n\\n\");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, renderAssignedTo, save;\n isEditable = function() {\n var _ref, _ref1;\n return ((_ref = $scope.project) != null ? (_ref1 = _ref.my_permissions) != null ? _ref1.indexOf($attrs.requiredPerm) : void 0 : void 0) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(userId) {\n var promise;\n $model.$modelValue.assigned_to = userId;\n $loading.start($el);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el);\n $confirm.notify(\"success\");\n renderAssignedTo($model.$modelValue);\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n $model.$modelValue.revert();\n $confirm.notify(\"error\");\n return $loading.finish($el);\n });\n return promise;\n };\n })(this));\n renderAssignedTo = function(issue) {\n var assignedTo, assignedToId, ctx, html;\n assignedToId = issue != null ? issue.assigned_to : void 0;\n assignedTo = assignedToId != null ? $scope.usersById[assignedToId] : null;\n ctx = {\n assignedTo: assignedTo,\n isEditable: isEditable()\n };\n html = template(ctx);\n return $el.html(html);\n };\n $el.on(\"click\", \".user-assigned\", function(event) {\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"assigned-to:add\", $model.$modelValue);\n });\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var title;\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n title = \"Are you sure you want to leave it unassigned?\";\n return $confirm.ask(title).then((function(_this) {\n return function(finish) {\n finish();\n $model.$modelValue.assigned_to = null;\n return save(null);\n };\n })(this));\n });\n $scope.$on(\"assigned-to:added\", function(ctx, userId, item) {\n if (item.id !== $model.$modelValue.id) {\n return;\n }\n return save(userId);\n });\n $scope.$watch($attrs.ngModel, function(instance) {\n return renderAssignedTo(instance);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgAssignedTo\", [\"$rootScope\", \"$tgConfirm\", \"$tgRepo\", \"$tgLoading\", \"$tgQqueue\", AssignedToDirective]);\n\n BlockButtonDirective = function($rootscope, $loading) {\n var link, template;\n template = \"Block\\nUnblock\";\n link = function($scope, $el, $attrs, $model) {\n var isEditable;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n $scope.$watch($attrs.ngModel, function(item) {\n if (!item) {\n return;\n }\n if (isEditable()) {\n $el.find('.item-block').addClass('editable');\n }\n if (item.is_blocked) {\n $el.find('.item-block').hide();\n return $el.find('.item-unblock').show();\n } else {\n $el.find('.item-block').show();\n return $el.find('.item-unblock').hide();\n }\n });\n $el.on(\"click\", \".item-block\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"block\", $model.$modelValue);\n });\n $el.on(\"click\", \".item-unblock\", function(event) {\n var finish;\n event.preventDefault();\n $loading.start($el.find(\".item-unblock\"));\n finish = function() {\n return $loading.finish($el.find(\".item-unblock\"));\n };\n return $rootscope.$broadcast(\"unblock\", $model.$modelValue, finish);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgBlockButton\", [\"$rootScope\", \"$tgLoading\", BlockButtonDirective]);\n\n DeleteButtonDirective = function($log, $repo, $confirm, $location) {\n var link, template;\n template = \"Delete\";\n link = function($scope, $el, $attrs, $model) {\n if (!$attrs.onDeleteGoToUrl) {\n return $log.error(\"DeleteButtonDirective requires on-delete-go-to-url set in scope.\");\n }\n if (!$attrs.onDeleteTitle) {\n return $log.error(\"DeleteButtonDirective requires on-delete-title set in scope.\");\n }\n $el.on(\"click\", \".button\", function(event) {\n var subtitle, title;\n title = $scope.$eval($attrs.onDeleteTitle);\n subtitle = $model.$modelValue.subject;\n return $confirm.askOnDelete(title, subtitle).then((function(_this) {\n return function(finish) {\n var promise;\n promise = $repo.remove($model.$modelValue);\n promise.then(function() {\n var url;\n finish();\n url = $scope.$eval($attrs.onDeleteGoToUrl);\n return $location.path(url);\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgDeleteButton\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", DeleteButtonDirective]);\n\n EditableSubjectDirective = function($rootscope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = \"
    \\n {{ item.subject }}\\n \\n
    \\n\";\n link = function($scope, $el, $attrs, $model) {\n var isEditable, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(subject) {\n var promise;\n $model.$modelValue.subject = subject;\n $loading.start($el.find('.save-container'));\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $el.find('.edit-subject').hide();\n return $el.find('.view-subject').show();\n });\n promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n return promise;\n };\n })(this));\n $el.click(function() {\n if (!isEditable()) {\n return;\n }\n $el.find('.edit-subject').show();\n $el.find('.view-subject').hide();\n return $el.find('input').focus();\n });\n $el.on(\"click\", \".save\", function() {\n var subject;\n subject = $scope.item.subject;\n return save(subject);\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var subject;\n if (event.keyCode === 13) {\n subject = $scope.item.subject;\n return save(subject);\n } else if (event.keyCode === 27) {\n $scope.$apply((function(_this) {\n return function() {\n return $model.$modelValue.revert();\n };\n })(this));\n $el.find('div.edit-subject').hide();\n return $el.find('div.view-subject').show();\n }\n });\n $el.find('div.edit-subject').hide();\n $el.find('div.view-subject span.edit').hide();\n $scope.$watch($attrs.ngModel, function(value) {\n if (!value) {\n return;\n }\n $scope.item = value;\n if (!isEditable()) {\n return $el.find('.view-subject .edit').remove();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgEditableSubject\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", EditableSubjectDirective]);\n\n EditableDescriptionDirective = function($rootscope, $repo, $confirm, $compile, $loading, $selectedText, $qqueue) {\n var link, noDescriptionMegEditMode, noDescriptionMegReadMode, template;\n template = \"
    \\n
    \\n \\n
    \\n
    \";\n noDescriptionMegEditMode = \"

    \\n Empty space is so boring...\\n go on be descriptive...\\n A rose by any other name would smell as sweet...\\n

    \";\n noDescriptionMegReadMode = \"

    \\n No description yet.\\n

    \";\n link = function($scope, $el, $attrs, $model) {\n var isEditable, save;\n $el.find('.edit-description').hide();\n $el.find('.view-description .edit').hide();\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(description) {\n var promise;\n $model.$modelValue.description = description;\n $loading.start($el.find('.save-container'));\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $el.find('.edit-description').hide();\n return $el.find('.view-description').show();\n });\n promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n };\n })(this));\n $el.on(\"mouseup\", \".view-description\", function(event) {\n var target;\n target = angular.element(event.target);\n if (!isEditable()) {\n return;\n }\n if (target.is('a')) {\n return;\n }\n if ($selectedText.get().length) {\n return;\n }\n $el.find('.edit-description').show();\n $el.find('.view-description').hide();\n return $el.find('textarea').focus();\n });\n $el.on(\"click\", \".save\", function() {\n var description;\n description = $scope.item.description;\n return save(description);\n });\n $el.on(\"keydown\", \"textarea\", function(event) {\n if (event.keyCode === 27) {\n $scope.$apply((function(_this) {\n return function() {\n return $scope.item.revert();\n };\n })(this));\n $el.find('.edit-description').hide();\n return $el.find('.view-description').show();\n }\n });\n $scope.$watch($attrs.ngModel, function(value) {\n if (!value) {\n return;\n }\n $scope.item = value;\n if (isEditable()) {\n $el.find('.view-description .edit').show();\n $el.find('.view-description .us-content').addClass('editable');\n return $scope.noDescriptionMsg = noDescriptionMegEditMode;\n } else {\n return $scope.noDescriptionMsg = noDescriptionMegReadMode;\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgEditableDescription\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$compile\", \"$tgLoading\", \"$selectedText\", \"$tgQqueue\", EditableDescriptionDirective]);\n\n ListItemIssueStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemIssueStatus);\n return bindOnce($scope, \"issueStatusById\", function(issueStatusById) {\n return $el.html(issueStatusById[issue.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemTaskStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var task;\n task = $scope.$eval($attrs.tgListitemTaskStatus);\n return bindOnce($scope, \"taskStatusById\", function(taskStatusById) {\n return $el.html(taskStatusById[task.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemUsStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var us;\n us = $scope.$eval($attrs.tgListitemUsStatus);\n return bindOnce($scope, \"usStatusById\", function(usStatusById) {\n return $el.html(usStatusById[us.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemAssignedtoDirective = function() {\n var link, template;\n template = _.template(\"
    \\n \\\" alt=\\\"<%- name %>\\\"/>\\n
    <%- name %>
    \\n
    \");\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, \"membersById\", function(membersById) {\n var ctx, item, member;\n item = $scope.$eval($attrs.tgListitemAssignedto);\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = membersById[item.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name;\n }\n return $el.html(template(ctx));\n });\n };\n return {\n link: link\n };\n };\n\n ListItemPriorityDirective = function() {\n var link, template;\n template = \"
    \";\n link = function($scope, $el, $attrs) {\n var render;\n render = function(priorityById, issue) {\n var domNode, priority;\n priority = priorityById[issue.priority];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", priority.color);\n return domNode.attr(\"title\", priority.name);\n };\n bindOnce($scope, \"priorityById\", function(priorityById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemPriority);\n return render(priorityById, issue);\n });\n return $scope.$watch($attrs.tgListitemPriority, function(issue) {\n return render($scope.priorityById, issue);\n });\n };\n return {\n link: link,\n template: template\n };\n };\n\n ListItemSeverityDirective = function() {\n var link, template;\n template = \"
    \";\n link = function($scope, $el, $attrs) {\n var render;\n render = function(severityById, issue) {\n var domNode, severity;\n severity = severityById[issue.severity];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", severity.color);\n return domNode.attr(\"title\", severity.name);\n };\n bindOnce($scope, \"severityById\", function(severityById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemSeverity);\n return render(severityById, issue);\n });\n return $scope.$watch($attrs.tgListitemSeverity, function(issue) {\n return render($scope.severityById, issue);\n });\n };\n return {\n link: link,\n template: template\n };\n };\n\n ListItemTypeDirective = function() {\n var link, template;\n template = \"
    \";\n link = function($scope, $el, $attrs) {\n var render;\n render = function(issueTypeById, issue) {\n var domNode, type;\n type = issueTypeById[issue.type];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", type.color);\n return domNode.attr(\"title\", type.name);\n };\n bindOnce($scope, \"issueTypeById\", function(issueTypeById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemType);\n return render(issueTypeById, issue);\n });\n return $scope.$watch($attrs.tgListitemType, function(issue) {\n return render($scope.issueTypeById, issue);\n });\n };\n return {\n link: link,\n template: template\n };\n };\n\n TgProgressBarDirective = function() {\n var link, render, template;\n template = _.template(\"
    %\\\">
    \");\n render = function(el, percentage) {\n return el.html(template({\n percentage: percentage\n }));\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch($attrs.tgProgressBar, function(percentage) {\n percentage = _.max([0, percentage]);\n percentage = _.min([100, percentage]);\n return render($el, percentage);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n TgMainTitleDirective = function() {\n var link, render, template;\n template = _.template(\"<%- projectName %>\\n<%- sectionName %>\");\n render = function(el, projectName, sectionName) {\n return el.html(template({\n projectName: projectName,\n sectionName: sectionName\n }));\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch(\"project\", function(project) {\n if (project) {\n return render($el, project.name, $scope.sectionName);\n }\n });\n $scope.$on(\"project:loaded\", (function(_this) {\n return function(ctx, project) {\n return render($el, project.name, $scope.sectionName);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgListitemType\", ListItemTypeDirective);\n\n module.directive(\"tgListitemIssueStatus\", ListItemIssueStatusDirective);\n\n module.directive(\"tgListitemAssignedto\", ListItemAssignedtoDirective);\n\n module.directive(\"tgListitemPriority\", ListItemPriorityDirective);\n\n module.directive(\"tgListitemSeverity\", ListItemSeverityDirective);\n\n module.directive(\"tgListitemTaskStatus\", ListItemTaskStatusDirective);\n\n module.directive(\"tgListitemUsStatus\", ListItemUsStatusDirective);\n\n module.directive(\"tgProgressBar\", TgProgressBarDirective);\n\n module.directive(\"tgMainTitle\", TgMainTitleDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/confirm.coffee\n */\n\n(function() {\n var ConfirmService, NOTIFICATION_MSG, bindMethods, cancelTimeout, debounce, module, taiga, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n timeout = this.taiga.timeout;\n\n cancelTimeout = this.taiga.cancelTimeout;\n\n debounce = this.taiga.debounce;\n\n bindMethods = this.taiga.bindMethods;\n\n NOTIFICATION_MSG = {\n \"success\": {\n title: \"Everything is ok\",\n message: \"Our Oompa Loompas saved all your changes!\"\n },\n \"error\": {\n title: \"Oops, something happened...\",\n message: \"Our Oompa Loompas are sad, your changes were not saved!\"\n },\n \"light-error\": {\n title: \"Oops, something happened...\",\n message: \"Our Oompa Loompas are sad, your changes were not saved!\"\n }\n };\n\n ConfirmService = (function(_super) {\n __extends(ConfirmService, _super);\n\n ConfirmService.$inject = [\"$q\", \"lightboxService\", \"$tgLoading\"];\n\n function ConfirmService(q, lightboxService, loading) {\n this.q = q;\n this.lightboxService = lightboxService;\n this.loading = loading;\n bindMethods(this);\n }\n\n ConfirmService.prototype.hide = function(el) {\n if (el) {\n this.lightboxService.close(el);\n return el.off(\".confirm-dialog\");\n }\n };\n\n ConfirmService.prototype.ask = function(title, subtitle, message, lightboxSelector) {\n var defered, el;\n if (lightboxSelector == null) {\n lightboxSelector = \".lightbox-generic-ask\";\n }\n el = angular.element(lightboxSelector);\n el.find(\"h2.title\").html(title);\n el.find(\"span.subtitle\").html(subtitle);\n el.find(\"span.message\").html(message);\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", debounce(2000, (function(_this) {\n return function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n _this.loading.start(target);\n return defered.resolve(function(ok) {\n if (ok == null) {\n ok = true;\n }\n _this.loading.finish(target);\n if (ok) {\n return _this.hide(el);\n }\n });\n };\n })(this)));\n el.on(\"click.confirm-dialog\", \"a.button-red\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.reject();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.askOnDelete = function(title, message) {\n return this.ask(title, \"Are you sure you want to delete?\", message);\n };\n\n ConfirmService.prototype.askChoice = function(title, subtitle, choices, replacement, warning, lightboxSelector) {\n var choicesField, defered, el;\n if (lightboxSelector == null) {\n lightboxSelector = \".lightbox-ask-choice\";\n }\n el = angular.element(lightboxSelector);\n el.find(\".title\").html(title);\n el.find(\".subtitle\").html(subtitle);\n if (replacement) {\n el.find(\".replacement\").html(replacement);\n } else {\n el.find(\".replacement\").remove();\n }\n if (warning) {\n el.find(\".warning\").html(warning);\n } else {\n el.find(\".warning\").remove();\n }\n choicesField = el.find(\".choices\");\n choicesField.html('');\n _.each(choices, function(value, key) {\n return choicesField.append(angular.element(\"\"));\n });\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", debounce(2000, (function(_this) {\n return function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n _this.loading.start(target);\n return defered.resolve({\n selected: choicesField.val(),\n finish: function() {\n _this.loading.finish(target);\n return _this.hide(el);\n }\n });\n };\n })(this)));\n el.on(\"click.confirm-dialog\", \"a.button-red\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.reject();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.error = function(message) {\n var defered, el;\n el = angular.element(\".lightbox-generic-error\");\n el.find(\"h2.title\").html(message);\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n el.on(\"click.confirm-dialog\", \"a.close\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.success = function(message) {\n var defered, el;\n el = angular.element(\".lightbox-generic-success\");\n el.find(\"h2.title\").html(message);\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n el.on(\"click.confirm-dialog\", \"a.close\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.notify = function(type, message, title, time) {\n var body, el, selector;\n selector = \".notification-message-\" + type;\n el = angular.element(selector);\n if (el.hasClass(\"active\")) {\n return;\n }\n if (title) {\n el.find(\"h4\").html(title);\n } else {\n el.find(\"h4\").html(NOTIFICATION_MSG[type].title);\n }\n if (message) {\n el.find(\"p\").html(message);\n } else {\n el.find(\"p\").html(NOTIFICATION_MSG[type].message);\n }\n body = angular.element(\"body\");\n body.find(\".notification-message .notification-light\").removeClass('active').addClass('inactive');\n body.find(selector).removeClass('inactive').addClass('active');\n if (this.tsem) {\n cancelTimeout(this.tsem);\n }\n if (!time) {\n time = type === 'error' || type === 'light-error' ? 3500 : 1500;\n }\n this.tsem = timeout(time, (function(_this) {\n return function() {\n body.find(selector).removeClass('active').addClass('inactive');\n return delete _this.tsem;\n };\n })(this));\n return el.on(\"click\", \".icon-delete\", (function(_this) {\n return function(event) {\n return body.find(selector).removeClass('active').addClass('inactive');\n };\n })(this));\n };\n\n return ConfirmService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaCommon\");\n\n module.service(\"$tgConfirm\", ConfirmService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/estimation.coffee\n */\n\n(function() {\n var LbUsEstimationDirective, UsEstimationDirective, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n LbUsEstimationDirective = function($rootScope, $repo, $confirm) {\n var link, mainTemplate, pointsTemplate;\n mainTemplate = _.template(\"
      \\n
    • \\n <%- totalPoints %>\\n total\\n
    • \\n <% _.each(roles, function(role) { %>\\n
    • \\\">\\n <%- role.points %>\\n <%- role.name %>
    • \\n <% }); %>\\n
    \");\n pointsTemplate = _.template(\"
    \");\n link = function($scope, $el, $attrs, $model) {\n var calculateTotalPoints, render, renderPoints;\n render = function(points) {\n var computableRoles, ctx, html, roles, totalPoints;\n totalPoints = calculateTotalPoints(points) || 0;\n computableRoles = _.filter($scope.project.roles, \"computable\");\n roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = (pointObj != null) && (pointObj.name != null) ? pointObj.name : \"?\";\n return role;\n });\n ctx = {\n totalPoints: totalPoints,\n roles: roles\n };\n html = mainTemplate(ctx);\n return $el.html(html);\n };\n renderPoints = function(target, usPoints, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = usPoints[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points,\n roleId: roleId\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n $el.find(\".pop-points-open\").remove();\n $el.find(target).append(html);\n $el.find(\".pop-points-open\").popover().open(function() {\n return $(this).removeClass(\"active\");\n });\n return $el.find(\".pop-points-open\").show();\n };\n calculateTotalPoints = function(points) {\n var values;\n values = _.map(points, function(v, k) {\n var _ref;\n return ((_ref = $scope.pointsById[v]) != null ? _ref.value : void 0) || 0;\n });\n if (values.length === 0) {\n return \"0\";\n }\n return _.reduce(values, function(acc, num) {\n return acc + num;\n });\n };\n $el.on(\"click\", \".total.clickable\", function(event) {\n var points, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n points = $model.$modelValue;\n renderPoints(target, points, roleId);\n target.siblings().removeClass('active');\n return target.addClass('active');\n });\n $el.on(\"click\", \".point\", function(event) {\n var pointId, points, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n pointId = target.data(\"point-id\");\n $el.find(\".popover\").popover().close();\n points = _.clone($model.$modelValue, true);\n points[roleId] = pointId;\n return $scope.$apply(function() {\n return $model.$setViewValue(points);\n });\n });\n $scope.$watch($attrs.ngModel, function(points) {\n if (points) {\n return render(points);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgLbUsEstimation\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", LbUsEstimationDirective]);\n\n UsEstimationDirective = function($rootScope, $repo, $confirm, $qqueue) {\n var link, mainTemplate, pointsTemplate;\n mainTemplate = _.template(\"
      \\n
    • \\n <%- totalPoints %>\\n total\\n
    • \\n <% _.each(roles, function(role) { %>\\n
    • clickable<% } %>\\\" data-role-id=\\\"<%- role.id %>\\\">\\n <%- role.points %>\\n <%- role.name %>
    • \\n <% }); %>\\n
    \");\n pointsTemplate = _.template(\"\");\n link = function($scope, $el, $attrs, $model) {\n var calculateTotalPoints, isEditable, render, renderPoints, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var computableRoles, ctx, html, roles, totalPoints;\n totalPoints = us.total_points != null ? us.total_points : \"?\";\n computableRoles = _.filter($scope.project.roles, \"computable\");\n roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = us.points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = (pointObj != null) && (pointObj.name != null) ? pointObj.name : \"?\";\n return role;\n });\n ctx = {\n totalPoints: totalPoints,\n roles: roles,\n editable: isEditable()\n };\n html = mainTemplate(ctx);\n return $el.html(html);\n };\n renderPoints = function(target, us, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = us.points[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points,\n roleId: roleId\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n $el.find(\".pop-points-open\").remove();\n $el.find(target).append(html);\n $el.find(\".pop-points-open\").popover().open(function() {\n return $(this).removeClass(\"active\").closest(\"li\").removeClass(\"active\");\n });\n return $el.find(\".pop-points-open\").show();\n };\n calculateTotalPoints = function(us) {\n var notNullValues, values;\n values = _.map(us.points, function(v, k) {\n var _ref;\n return (_ref = $scope.pointsById[v]) != null ? _ref.value : void 0;\n });\n if (values.length === 0) {\n return \"0\";\n }\n notNullValues = _.filter(values, function(v) {\n return v != null;\n });\n if (notNullValues.length === 0) {\n return \"?\";\n }\n return _.reduce(notNullValues, function(acc, num) {\n return acc + num;\n });\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(roleId, pointId) {\n var onError, onSuccess, points, us;\n $el.find(\".popover\").popover().close();\n us = angular.copy($model.$modelValue);\n points = _.clone($model.$modelValue.points, true);\n points[roleId] = pointId;\n us.setAttr('points', points);\n us.points = points;\n us.total_points = calculateTotalPoints(us);\n $model.$setViewValue(us);\n onSuccess = function() {\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n };\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".total.clickable\", function(event) {\n var roleId, target, us;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n us = $model.$modelValue;\n renderPoints(target, us, roleId);\n target.siblings().removeClass('active');\n return target.addClass('active');\n });\n $el.on(\"click\", \".point\", function(event) {\n var pointId, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n pointId = target.data(\"point-id\");\n return save(roleId, pointId);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsEstimation\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgQqueue\", UsEstimationDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/filters.coffee\n */\n\n(function() {\n var defaultFilter, module, momentFormat, momentFromNow, taiga, unslugify, yesNoFilter;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n defaultFilter = function() {\n return function(value, defaultValue) {\n if (value === [null, void 0]) {\n return defaultValue;\n }\n return value;\n };\n };\n\n module.filter(\"default\", defaultFilter);\n\n yesNoFilter = function() {\n return function(value) {\n if (value) {\n return \"Yes\";\n }\n return \"No\";\n };\n };\n\n module.filter(\"yesNo\", yesNoFilter);\n\n unslugify = function() {\n return taiga.unslugify;\n };\n\n module.filter(\"unslugify\", unslugify);\n\n momentFormat = function() {\n return function(input, format) {\n if (input) {\n return moment(input).format(format);\n }\n return \"\";\n };\n };\n\n module.filter(\"momentFormat\", momentFormat);\n\n momentFromNow = function() {\n return function(input, without_suffix) {\n if (input) {\n return moment(input).fromNow(without_suffix || false);\n }\n return \"\";\n };\n };\n\n module.filter(\"momentFromNow\", momentFromNow);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/history.coffee\n */\n\n(function() {\n var HistoryController, HistoryDirective, bindOnce, debounce, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaCommon\");\n\n HistoryController = (function(_super) {\n __extends(HistoryController, _super);\n\n HistoryController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\"];\n\n function HistoryController(scope, repo, rs) {\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n }\n\n HistoryController.prototype.initialize = function(type, objectId) {\n this.type = type;\n return this.objectId = objectId;\n };\n\n HistoryController.prototype.loadHistory = function(type, objectId) {\n return this.rs.history.get(type, objectId).then((function(_this) {\n return function(history) {\n var historyResult, _i, _len;\n for (_i = 0, _len = history.length; _i < _len; _i++) {\n historyResult = history[_i];\n if (historyResult.values_diff.description_diff != null) {\n historyResult.values_diff.description = historyResult.values_diff.description_diff;\n }\n delete historyResult.values_diff.description_html;\n delete historyResult.values_diff.description_diff;\n }\n _this.scope.history = history;\n return _this.scope.comments = _.filter(history, function(item) {\n return item.comment !== \"\";\n });\n };\n })(this));\n };\n\n HistoryController.prototype.deleteComment = function(type, objectId, activityId) {\n return this.rs.history.deleteComment(type, objectId, activityId).then((function(_this) {\n return function() {\n return _this.loadHistory(type, objectId);\n };\n })(this));\n };\n\n HistoryController.prototype.undeleteComment = function(type, objectId, activityId) {\n return this.rs.history.undeleteComment(type, objectId, activityId).then((function(_this) {\n return function() {\n return _this.loadHistory(type, objectId);\n };\n })(this));\n };\n\n return HistoryController;\n\n })(taiga.Controller);\n\n HistoryDirective = function($log, $loading, $qqueue) {\n var link, templateActivity, templateBase, templateBaseEntries, templateChangeAttachment, templateChangeDiff, templateChangeGeneric, templateChangePoints, templateDeletedComment, templateFn;\n templateChangeDiff = _.template(\"
    \\n
    \\n <%- name %>\\n
    \\n
    \\n

    \\n <%= diff %>\\n

    \\n
    \\n
    \");\n templateChangePoints = _.template(\"<% _.each(points, function(point, name) { %>\\n
    \\n
    \\n US points (<%- name.toLowerCase() %>)\\n
    \\n
    \\n

    \\n from
    \\n <%- point[0] %>\\n

    \\n

    \\n to
    \\n <%- point[1] %>\\n

    \\n
    \\n
    \\n<% }); %>\");\n templateChangeGeneric = _.template(\"
    \\n
    \\n <%- name %>\\n
    \\n
    \\n

    \\n from
    \\n <%- from %>\\n

    \\n

    \\n to
    \\n <%- to %>\\n

    \\n
    \\n
    \");\n templateChangeAttachment = _.template(\"
    \\n
    \\n <%- name %>\\n
    \\n
    \\n <% _.each(diff, function(change) { %>\\n

    \\n <%- change.name %> from
    \\n <%- change.from %>\\n

    \\n

    \\n <%- change.name %> to
    \\n <%- change.to %>\\n

    \\n <% }) %>\\n
    \\n
    \");\n templateDeletedComment = _.template(\"
    \\n
    \\n Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>\\n (Show deleted comment)\\n (Hide deleted comment)\\n
    <%= deleteComment %>
    \\n
    \\n <% if (canRestoreComment) { %>\\n \\\">\\n \\n Restore comment\\n \\n <% } %>\\n
    \");\n templateActivity = _.template(\"
    \\\">\\n \\n
    \\n
    \\n \\\">\\n <%- userFullName %>\\n \\n \\n <%- creationDate %>\\n \\n
    \\n\\n <% if (comment.length > 0) { %>\\n <% if ((deleteCommentDate || deleteCommentUser)) { %>\\n
    \\n Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>\\n
    \\n <% } %>\\n
    \\n <%= comment %>\\n
    \\n <% if (!deleteCommentDate && mode !== \\\"activity\\\" && canDeleteComment) { %>\\n \\\">\\n <% } %>\\n <% } %>\\n\\n <% if(changes.length > 0) { %>\\n
    \\n <% if (mode != \\\"activity\\\") { %>\\n \\n <%- changesText %>\\n \\n \\n <% } %>\\n\\n <% _.each(changes, function(change) { %>\\n <%= change %>\\n <% }) %>\\n
    \\n <% } %>\\n
    \\n
    \");\n templateBaseEntries = _.template(\"\\n<% if (showMore > 0) { %>\\n\\n+ Show previous entries (<%- showMore %> more)\\n\\n<% } %>\\n<% _.each(entries, function(entry) { %>\\n <%= entry %>\\n<% }) %>\");\n templateBase = _.template(\"
    \\n \\n
    \\n
    \\n
    \\\" tg-toggle-comment class=\\\"add-comment\\\">\\n \\n <% if (mode !== \\\"edit\\\") { %>\\n \\n \\n Markdown syntax help\\n \\n Comment\\n <% } %>\\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \");\n link = function($scope, $el, $attrs, $ctrl) {\n var countChanges, formatChange, getHumanizedFieldName, getUserAvatar, getUserFullName, objectId, renderActivity, renderAttachmentEntry, renderChange, renderChangeEntries, renderChangeEntry, renderChangesHelperText, renderComment, renderComments, renderHistory, save, showAllActivity, showAllComments, type;\n type = $attrs.type;\n objectId = null;\n showAllComments = false;\n showAllActivity = false;\n bindOnce($scope, $attrs.ngModel, function(model) {\n type = $attrs.type;\n objectId = model.id;\n $ctrl.initialize(type, objectId);\n return $ctrl.loadHistory(type, objectId);\n });\n getHumanizedFieldName = function(field) {\n var humanizedFieldNames;\n humanizedFieldNames = {\n assigned_to: \"assigned to\",\n is_closed: \"is closed\",\n finish_date: \"finish date\",\n client_requirement: \"client requirement\",\n team_requirement: \"team requirement\",\n milestone: \"sprint\",\n user_story: \"user story\",\n is_iocaine: \"is iocaine\",\n is_deprecated: \"is deprecated\"\n };\n return humanizedFieldNames[field] || field;\n };\n getUserFullName = function(userId) {\n var _ref;\n return (_ref = $scope.usersById[userId]) != null ? _ref.full_name_display : void 0;\n };\n getUserAvatar = function(userId) {\n if ($scope.usersById[userId] != null) {\n return $scope.usersById[userId].photo;\n } else {\n return \"/images/unnamed.png\";\n }\n };\n countChanges = function(comment) {\n return _.keys(comment.values_diff).length;\n };\n formatChange = function(change) {\n if (_.isArray(change)) {\n if (change.length === 0) {\n return \"nil\";\n }\n return change.join(\", \");\n }\n if (change === \"\") {\n return \"nil\";\n }\n if (change === true) {\n return \"yes\";\n }\n if (change === false) {\n return \"no\";\n }\n return change;\n };\n renderAttachmentEntry = function(value) {\n var attachments;\n attachments = _.map(value, function(changes, type) {\n if (type === \"new\") {\n return _.map(changes, function(change) {\n return templateChangeDiff({\n name: \"new attachment\",\n diff: change.filename\n });\n });\n } else if (type === \"deleted\") {\n return _.map(changes, function(change) {\n return templateChangeDiff({\n name: \"deleted attachment\",\n diff: change.filename\n });\n });\n } else {\n return _.map(changes, function(change) {\n var diff, name;\n name = \"updated attachment \" + change.filename;\n diff = _.map(change.changes, function(values, name) {\n return {\n name: getHumanizedFieldName(name),\n from: formatChange(values[0]),\n to: formatChange(values[1])\n };\n });\n return templateChangeAttachment({\n name: name,\n diff: diff\n });\n });\n }\n });\n return _.flatten(attachments).join(\"\\n\");\n };\n renderChangeEntry = function(field, value) {\n var from, name, to;\n if (field === \"description\") {\n return templateChangeDiff({\n name: \"description\",\n diff: value[1]\n });\n } else if (field === \"points\") {\n return templateChangePoints({\n points: value\n });\n } else if (field === \"attachments\") {\n return renderAttachmentEntry(value);\n } else if (field === \"assigned_to\") {\n name = getHumanizedFieldName(field);\n from = formatChange(value[0] || \"Unassigned\");\n to = formatChange(value[1] || \"Unassigned\");\n return templateChangeGeneric({\n name: name,\n from: from,\n to: to\n });\n } else {\n name = getHumanizedFieldName(field);\n from = formatChange(value[0]);\n to = formatChange(value[1]);\n return templateChangeGeneric({\n name: name,\n from: from,\n to: to\n });\n }\n };\n renderChangeEntries = function(change, join) {\n var entries;\n if (join == null) {\n join = true;\n }\n entries = _.map(change.values_diff, function(value, field) {\n return renderChangeEntry(field, value);\n });\n if (join) {\n return entries.join(\"\\n\");\n }\n return entries;\n };\n renderChangesHelperText = function(change) {\n var size;\n size = countChanges(change);\n if (size === 1) {\n return \"Made \" + size + \" change\";\n }\n return \"Made \" + size + \" changes\";\n };\n renderComment = function(comment) {\n var _ref;\n if (comment.delete_comment_date || comment.delete_comment_user) {\n return templateDeletedComment({\n deleteCommentDate: moment(comment.delete_comment_date).format(\"DD MMM YYYY HH:mm\"),\n deleteCommentUser: comment.delete_comment_user.name,\n deleteComment: comment.comment_html,\n activityId: comment.id,\n canRestoreComment: comment.delete_comment_user.pk === $scope.user.id || $scope.project.my_permissions.indexOf(\"modify_project\") > -1\n });\n }\n return templateActivity({\n avatar: getUserAvatar(comment.user.pk),\n userFullName: comment.user.name,\n creationDate: moment(comment.created_at).format(\"DD MMM YYYY HH:mm\"),\n comment: comment.comment_html,\n changesText: renderChangesHelperText(comment),\n changes: renderChangeEntries(comment, false),\n mode: \"comment\",\n deleteCommentDate: comment.delete_comment_date ? moment(comment.delete_comment_date).format(\"DD MMM YYYY HH:mm\") : void 0,\n deleteCommentUser: ((_ref = comment.delete_comment_user) != null ? _ref.name : void 0) ? comment.delete_comment_user.name : void 0,\n activityId: comment.id,\n canDeleteComment: comment.user.pk === $scope.user.id || $scope.project.my_permissions.indexOf(\"modify_project\") > -1\n });\n };\n renderChange = function(change) {\n var _ref;\n return templateActivity({\n avatar: getUserAvatar(change.user.pk),\n userFullName: change.user.name,\n creationDate: moment(change.created_at).format(\"DD MMM YYYY HH:mm\"),\n comment: change.comment_html,\n changes: renderChangeEntries(change, false),\n changesText: \"\",\n mode: \"activity\",\n deleteCommentDate: change.delete_comment_date ? moment(change.delete_comment_date).format(\"DD MMM YYYY HH:mm\") : void 0,\n deleteCommentUser: ((_ref = change.delete_comment_user) != null ? _ref.name : void 0) ? change.delete_comment_user.name : void 0,\n activityId: change.id\n });\n };\n renderHistory = function(entries, totalEntries) {\n var showMore;\n if (entries.length === totalEntries) {\n showMore = 0;\n } else {\n showMore = totalEntries - entries.length;\n }\n return templateBaseEntries({\n entries: entries,\n showMore: showMore\n });\n };\n renderComments = function() {\n var comments, html, totalComments;\n comments = $scope.comments || [];\n totalComments = comments.length;\n if (!showAllComments) {\n comments = _.last(comments, 4);\n }\n comments = _.map(comments, function(x) {\n return renderComment(x);\n });\n html = renderHistory(comments, totalComments);\n return $el.find(\".comments-list\").html(html);\n };\n renderActivity = function() {\n var changes, html, totalChanges;\n changes = $scope.history || [];\n totalChanges = changes.length;\n if (!showAllActivity) {\n changes = _.last(changes, 4);\n }\n changes = _.map(changes, function(x) {\n return renderChange(x);\n });\n html = renderHistory(changes, totalChanges);\n return $el.find(\".changes-list\").html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(target) {\n var model, onError, onSuccess;\n $scope.$broadcast(\"markdown-editor:submit\");\n $el.find(\".comment-list\").addClass(\"activeanimation\");\n onSuccess = function() {\n return $ctrl.loadHistory(type, objectId)[\"finally\"](function() {\n return $loading.finish(target);\n });\n };\n onError = function() {\n $loading.finish(target);\n return $confirm.notify(\"error\");\n };\n model = $scope.$eval($attrs.ngModel);\n $loading.start(target);\n return $ctrl.repo.save(model).then(onSuccess, onError);\n };\n })(this));\n $scope.$watch(\"comments\", renderComments);\n $scope.$watch(\"history\", renderActivity);\n $scope.$on(\"history:reload\", function() {\n return $ctrl.loadHistory(type, objectId);\n });\n $el.on(\"click\", \".add-comment a.button-green\", debounce(2000, function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return save(target);\n }));\n $el.on(\"click\", \".show-more\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n if (target.parent().is(\".changes-list\")) {\n showAllActivity = !showAllActivity;\n return renderActivity();\n } else {\n showAllComments = !showAllComments;\n return renderComments();\n }\n });\n $el.on(\"click\", \".show-deleted-comment\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.parents('.activity-single').find('.hide-deleted-comment').show();\n target.parents('.activity-single').find('.show-deleted-comment').hide();\n return target.parents('.activity-single').find('.comment-body').show();\n });\n $el.on(\"click\", \".hide-deleted-comment\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.parents('.activity-single').find('.hide-deleted-comment').hide();\n target.parents('.activity-single').find('.show-deleted-comment').show();\n return target.parents('.activity-single').find('.comment-body').hide();\n });\n $el.on(\"click\", \".changes-title\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return target.parent().find(\".change-entry\").toggleClass(\"active\");\n });\n $el.on(\"focus\", \".add-comment textarea\", function(event) {\n return $(this).addClass('active');\n });\n $el.on(\"click\", \".history-tabs li a\", function(event) {\n $el.find(\".history-tabs li a\").toggleClass(\"active\");\n return $el.find(\".history section\").toggleClass(\"hidden\");\n });\n $el.on(\"click\", \".comment-delete\", debounce(2000, function(event) {\n var activityId, target;\n target = angular.element(event.currentTarget);\n activityId = target.data('activity-id');\n return $ctrl.deleteComment(type, objectId, activityId);\n }));\n $el.on(\"click\", \".comment-restore\", debounce(2000, function(event) {\n var activityId, target;\n target = angular.element(event.currentTarget);\n activityId = target.data('activity-id');\n return $ctrl.undeleteComment(type, objectId, activityId);\n }));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n templateFn = function($el, $attrs) {\n return templateBase({\n ngmodel: $attrs.ngModel,\n type: $attrs.type,\n mode: $attrs.mode\n });\n };\n return {\n controller: HistoryController,\n template: templateFn,\n restrict: \"AE\",\n link: link\n };\n };\n\n module.directive(\"tgHistory\", [\"$log\", \"$tgLoading\", \"$tgQqueue\", HistoryDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/lightboxes.coffee\n */\n\n(function() {\n var AssignedToLightboxDirective, BlockLightboxDirective, BlockingMessageInputDirective, CreateBulkUserstoriesDirective, CreateEditUserstoryDirective, LightboxDirective, LightboxKeyboardNavigationService, LightboxService, NotionButtonDirective, NotionLightboxDirective, WatchersLightboxDirective, bindOnce, debounce, module, timeout, usersTemplate,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n module = angular.module(\"taigaCommon\");\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n debounce = this.taiga.debounce;\n\n LightboxService = (function(_super) {\n __extends(LightboxService, _super);\n\n function LightboxService(animationFrame) {\n this.animationFrame = animationFrame;\n }\n\n LightboxService.prototype.open = function($el) {\n var docEl, lightboxContent;\n lightboxContent = $el.children().not(\".close\");\n lightboxContent.hide();\n $el.css('display', 'flex');\n $el.find('input,textarea').first().focus();\n this.animationFrame.add((function(_this) {\n return function() {\n $el.addClass(\"open\");\n return lightboxContent.show();\n };\n })(this));\n docEl = angular.element(document);\n return docEl.on(\"keydown.lightbox\", (function(_this) {\n return function(e) {\n var code;\n code = e.keyCode ? e.keyCode : e.which;\n if (code === 27) {\n return _this.close($el);\n }\n };\n })(this));\n };\n\n LightboxService.prototype.close = function($el) {\n var docEl;\n docEl = angular.element(document);\n docEl.off(\".lightbox\");\n docEl.off(\".keyboard-navigation\");\n $el.one(\"transitionend\", (function(_this) {\n return function() {\n $el.removeAttr('style');\n return $el.removeClass(\"open\").removeClass('close');\n };\n })(this));\n return $el.addClass('close');\n };\n\n LightboxService.prototype.closeAll = function() {\n var docEl, lightboxEl, _i, _len, _ref, _results;\n docEl = angular.element(document);\n _ref = docEl.find(\".lightbox.open\");\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n lightboxEl = _ref[_i];\n _results.push(this.close($(lightboxEl)));\n }\n return _results;\n };\n\n return LightboxService;\n\n })(taiga.Service);\n\n module.service(\"lightboxService\", [\"animationFrame\", LightboxService]);\n\n LightboxKeyboardNavigationService = (function(_super) {\n __extends(LightboxKeyboardNavigationService, _super);\n\n function LightboxKeyboardNavigationService() {\n return LightboxKeyboardNavigationService.__super__.constructor.apply(this, arguments);\n }\n\n LightboxKeyboardNavigationService.prototype.stop = function() {\n var docEl;\n docEl = angular.element(document);\n return docEl.off(\".keyboard-navigation\");\n };\n\n LightboxKeyboardNavigationService.prototype.dispatch = function($el, code) {\n var activeElement, next, prev;\n activeElement = $el.find(\".active\");\n if (code === 13) {\n return activeElement.trigger(\"click\");\n } else if (code === 40) {\n if (!activeElement.length) {\n return $el.find('.watcher-single:first').addClass('active');\n } else {\n next = activeElement.next('.watcher-single');\n if (next.length) {\n activeElement.removeClass('active');\n return next.addClass('active');\n }\n }\n } else if (code === 38) {\n if (!activeElement.length) {\n return $el.find('.watcher-single:last').addClass('active');\n } else {\n prev = activeElement.prev('.watcher-single');\n if (prev.length) {\n activeElement.removeClass('active');\n return prev.addClass('active');\n }\n }\n }\n };\n\n LightboxKeyboardNavigationService.prototype.init = function($el) {\n var docEl;\n this.stop();\n docEl = angular.element(document);\n return docEl.on(\"keydown.keyboard-navigation\", (function(_this) {\n return function(event) {\n var code;\n code = event.keyCode ? event.keyCode : event.which;\n if (code === 40 || code === 38 || code === 13) {\n event.preventDefault();\n return _this.dispatch($el, code);\n }\n };\n })(this));\n };\n\n return LightboxKeyboardNavigationService;\n\n })(taiga.Service);\n\n module.service(\"lightboxKeyboardNavigationService\", LightboxKeyboardNavigationService);\n\n LightboxDirective = function(lightboxService) {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n };\n return {\n restrict: \"C\",\n link: link\n };\n };\n\n module.directive(\"lightbox\", [\"lightboxService\", LightboxDirective]);\n\n BlockLightboxDirective = function($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var block, unblock;\n $el.find(\"h2.title\").text($attrs.title);\n unblock = $qqueue.bindAdd((function(_this) {\n return function(item, finishCallback) {\n var promise;\n promise = $tgrepo.save(item);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $model.$setViewValue(item);\n return finishCallback();\n });\n promise.then(null, function() {\n $confirm.notify(\"error\");\n item.revert();\n return $model.$setViewValue(item);\n });\n promise[\"finally\"](function() {\n return finishCallback();\n });\n return promise;\n };\n })(this));\n block = $qqueue.bindAdd((function(_this) {\n return function(item) {\n var promise;\n $model.$setViewValue(item);\n $loading.start($el.find(\".button-green\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n $confirm.notify(\"error\");\n item.revert();\n return $model.$setViewValue(item);\n });\n return promise[\"finally\"](function() {\n $loading.finish($el.find(\".button-green\"));\n return lightboxService.close($el);\n });\n };\n })(this));\n $scope.$on(\"block\", function() {\n $el.find(\".reason\").val($model.$modelValue.blocked_note);\n return lightboxService.open($el);\n });\n $scope.$on(\"unblock\", (function(_this) {\n return function(event, model, finishCallback) {\n var item;\n item = $model.$modelValue.clone();\n item.is_blocked = false;\n item.blocked_note = \"\";\n return unblock(item, finishCallback);\n };\n })(this));\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return $el.on(\"click\", \".button-green\", function(event) {\n var item;\n event.preventDefault();\n item = $model.$modelValue.clone();\n item.is_blocked = true;\n item.blocked_note = $el.find(\".reason\").val();\n return block(item);\n });\n };\n return {\n templateUrl: \"/partials/views/modules/lightbox-block.html\",\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgLbBlock\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"lightboxService\", \"$tgLoading\", \"$tgQqueue\", BlockLightboxDirective]);\n\n BlockingMessageInputDirective = function($log) {\n var link, template, templateFn;\n template = _.template(\"
    \\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n if (!$attrs.watch) {\n return $log.error(\"No watch attribute on tg-blocking-message-input directive\");\n }\n return $scope.$watch($attrs.watch, function(value) {\n if (value === !void 0 && value === true) {\n return $el.find(\".blocked-note\").removeClass(\"hidden\");\n } else {\n return $el.find(\".blocked-note\").addClass(\"hidden\");\n }\n });\n };\n templateFn = function($el, $attrs) {\n return template({\n ngmodel: $attrs.ngModel\n });\n };\n return {\n template: templateFn,\n link: link,\n require: \"ngModel\",\n restrict: \"EA\"\n };\n };\n\n module.directive(\"tgBlockingMessageInput\", [\"$log\", BlockingMessageInputDirective]);\n\n CreateEditUserstoryDirective = function($repo, $model, $rs, $rootScope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.isNew = true;\n $scope.$on(\"usform:new\", function(ctx, projectId, status, statusList) {\n $scope.isNew = true;\n $scope.usStatusList = statusList;\n $scope.us = $model.make_model(\"userstories\", {\n project: projectId,\n points: {},\n status: status,\n is_archived: false,\n tags: []\n });\n $el.find(\".button-green\").html(\"Create\");\n $el.find(\".title\").html(\"New user story \");\n $el.find(\".tag-input\").val(\"\");\n $el.find(\".blocked-note\").addClass(\"hidden\");\n $el.find(\"label.blocked\").removeClass(\"selected\");\n $el.find(\"label.team-requirement\").removeClass(\"selected\");\n $el.find(\"label.client-requirement\").removeClass(\"selected\");\n return lightboxService.open($el);\n });\n $scope.$on(\"usform:edit\", function(ctx, us) {\n $scope.us = us;\n $scope.isNew = false;\n $el.find(\".button-green\").html(\"Save\");\n $el.find(\".title\").html(\"Edit user story \");\n $el.find(\".tag-input\").val(\"\");\n if (us.is_blocked) {\n $el.find(\".blocked-note\").removeClass(\"hidden\");\n $el.find(\"label.blocked\").addClass(\"selected\");\n } else {\n $el.find(\".blocked-note\").addClass(\"hidden\");\n $el.find(\"label.blocked\").removeClass(\"selected\");\n }\n if (us.team_requirement) {\n $el.find(\"label.team-requirement\").addClass(\"selected\");\n } else {\n $el.find(\"label.team-requirement\").removeClass(\"selected\");\n }\n if (us.client_requirement) {\n $el.find(\"label.client-requirement\").addClass(\"selected\");\n } else {\n $el.find(\"label.client-requirement\").removeClass(\"selected\");\n }\n return lightboxService.open($el);\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n if ($scope.isNew) {\n promise = $repo.create(\"userstories\", $scope.us);\n broadcastEvent = \"usform:new:success\";\n } else {\n promise = $repo.save($scope.us);\n broadcastEvent = \"usform:edit:success\";\n }\n promise.then(function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n return $rootScope.$broadcast(broadcastEvent, data);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n $scope.$apply(function() {\n return $scope.us.revert();\n });\n return lightboxService.close($el);\n });\n $el.keydown(function(event) {\n var code;\n code = event.keyCode ? event.keyCode : event.which;\n if (code === 27) {\n lightboxService.close($el);\n return $scope.$apply(function() {\n return $scope.us.revert();\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateEditUserstory\", [\"$tgRepo\", \"$tgModel\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateEditUserstoryDirective]);\n\n CreateBulkUserstoriesDirective = function($repo, $rs, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.$on(\"usform:bulk\", function(ctx, projectId, status) {\n $scope[\"new\"] = {\n projectId: projectId,\n statusId: status,\n bulk: \"\"\n };\n return lightboxService.open($el);\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley({\n onlyOneErrorElement: true\n });\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $rs.userstories.bulkCreate($scope[\"new\"].projectId, $scope[\"new\"].statusId, $scope[\"new\"].bulk);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"usform:bulk:success\", result);\n return lightboxService.close($el);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateBulkUserstories\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateBulkUserstoriesDirective]);\n\n usersTemplate = _.template(\"<% if (selected) { %>\\n\\n<% } %>\\n\\n<% _.each(users, function(user) { %>\\n\\n<% }) %>\\n\\n<% if (showMore) { %>\\n
    \\n ...too many users, keep filtering\\n
    \\n<% } %>\");\n\n AssignedToLightboxDirective = function(lightboxService, lightboxKeyboardNavigationService) {\n var link;\n link = function($scope, $el, $attrs) {\n var closeLightbox, filterUsers, normalizeString, render, selectedItem, selectedUser;\n selectedUser = null;\n selectedItem = null;\n normalizeString = function(string) {\n var normalizedString;\n normalizedString = string;\n normalizedString = normalizedString.replace(\"Á\", \"A\").replace(\"Ä\", \"A\").replace(\"À\", \"A\");\n normalizedString = normalizedString.replace(\"É\", \"E\").replace(\"Ë\", \"E\").replace(\"È\", \"E\");\n normalizedString = normalizedString.replace(\"Í\", \"I\").replace(\"Ï\", \"I\").replace(\"Ì\", \"I\");\n normalizedString = normalizedString.replace(\"Ó\", \"O\").replace(\"Ö\", \"O\").replace(\"Ò\", \"O\");\n normalizedString = normalizedString.replace(\"Ú\", \"U\").replace(\"Ü\", \"U\").replace(\"Ù\", \"U\");\n return normalizedString;\n };\n filterUsers = function(text, user) {\n var username;\n username = user.full_name_display.toUpperCase();\n username = normalizeString(username);\n text = text.toUpperCase();\n text = normalizeString(text);\n return _.contains(username, text);\n };\n render = function(selected, text) {\n var ctx, html, users;\n $el.find(\"input\").focus();\n users = _.clone($scope.activeUsers, true);\n if (selected != null) {\n users = _.reject(users, {\n \"id\": selected.id\n });\n }\n if (text != null) {\n users = _.filter(users, _.partial(filterUsers, text));\n }\n ctx = {\n selected: selected,\n users: _.first(users, 5),\n showMore: users.length > 5\n };\n html = usersTemplate(ctx);\n $el.find(\"div.watchers\").html(html);\n return lightboxKeyboardNavigationService.init($el);\n };\n closeLightbox = function() {\n lightboxKeyboardNavigationService.stop();\n return lightboxService.close($el);\n };\n $scope.$on(\"assigned-to:add\", function(ctx, item) {\n var assignedToId;\n selectedItem = item;\n assignedToId = item.assigned_to;\n selectedUser = $scope.usersById[assignedToId];\n render(selectedUser);\n lightboxService.open($el);\n return $el.find('input').focus();\n });\n $scope.$watch(\"usersSearch\", function(searchingText) {\n if (searchingText != null) {\n return render(selectedUser, searchingText);\n }\n });\n $el.on(\"click\", \".watcher-single\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n closeLightbox();\n return $scope.$apply(function() {\n $scope.$broadcast(\"assigned-to:added\", target.data(\"user-id\"), selectedItem);\n return $scope.usersSearch = null;\n });\n });\n $el.on(\"click\", \".remove-assigned-to\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n closeLightbox();\n return $scope.$apply(function() {\n $scope.usersSearch = null;\n return $scope.$broadcast(\"assigned-to:added\", null, selectedItem);\n });\n });\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n closeLightbox();\n return $scope.$apply(function() {\n return $scope.usersSearch = null;\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"/partials/views/modules/lightbox-assigned-to.html\",\n link: link\n };\n };\n\n module.directive(\"tgLbAssignedto\", [\"lightboxService\", \"lightboxKeyboardNavigationService\", AssignedToLightboxDirective]);\n\n WatchersLightboxDirective = function($repo, lightboxService, lightboxKeyboardNavigationService) {\n var link;\n link = function($scope, $el, $attrs) {\n var closeLightbox, getFilteredUsers, render, selectedItem;\n selectedItem = null;\n getFilteredUsers = function(text) {\n var users, _filterUsers;\n if (text == null) {\n text = \"\";\n }\n _filterUsers = function(text, user) {\n var username;\n if (selectedItem && _.find(selectedItem.watchers, function(x) {\n return x === user.id;\n })) {\n return false;\n }\n username = user.full_name_display.toUpperCase();\n text = text.toUpperCase();\n return _.contains(username, text);\n };\n users = _.clone($scope.activeUsers, true);\n users = _.filter(users, _.partial(_filterUsers, text));\n return users;\n };\n render = function(users) {\n var ctx, html;\n $el.find(\"input\").focus();\n ctx = {\n selected: false,\n users: _.first(users, 5),\n showMore: users.length > 5\n };\n html = usersTemplate(ctx);\n return $el.find(\"div.watchers\").html(html);\n };\n closeLightbox = function() {\n lightboxKeyboardNavigationService.stop();\n return lightboxService.close($el);\n };\n $scope.$on(\"watcher:add\", function(ctx, item) {\n var users;\n selectedItem = item;\n users = getFilteredUsers();\n render(users);\n lightboxService.open($el);\n return lightboxKeyboardNavigationService.init($el);\n });\n $scope.$watch(\"usersSearch\", function(searchingText) {\n var users;\n if (searchingText == null) {\n return;\n }\n users = getFilteredUsers(searchingText);\n return render(users);\n });\n $el.on(\"click\", \".watcher-single\", debounce(2000, function(event) {\n var target;\n closeLightbox();\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return $scope.$apply(function() {\n $scope.usersSearch = null;\n return $scope.$broadcast(\"watcher:added\", target.data(\"user-id\"));\n });\n }));\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n closeLightbox();\n return $scope.$apply(function() {\n return $scope.usersSearch = null;\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"/partials/views/modules/lightbox-users.html\",\n link: link\n };\n };\n\n module.directive(\"tgLbWatchers\", [\"$tgRepo\", \"lightboxService\", \"lightboxKeyboardNavigationService\", WatchersLightboxDirective]);\n\n NotionLightboxDirective = function(lightboxService) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $scope.$on(\"notion:open\", function(event, lightboxId) {\n if ($el.attr(\"id\") === lightboxId) {\n return lightboxService.open($el);\n }\n });\n $el.on(\"click\", \".button-green\", function(event) {\n return lightboxService.close($el);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbNotion\", [\"lightboxService\", NotionLightboxDirective]);\n\n NotionButtonDirective = function($log, $rootScope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n if ($attrs.tgLbNotionButton == null) {\n return $log.error(\"NotionButtonDirective: the directive need the id of the notion lightbox\");\n }\n $el.on(\"click\", function() {\n return $rootScope.$broadcast(\"notion:open\", $attrs.tgLbNotionButton);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbNotionButton\", [\"$log\", \"$rootScope\", NotionButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n * Copyright (C) 2014 Juan Francisco Alcántara \n * Copyright (C) 2014 Alejandro Alonso \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/loader.coffee\n */\n\n(function() {\n var Loader, LoaderDirective, module, sizeFormat, taiga, timeout;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaCommon\");\n\n LoaderDirective = function(tgLoader, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n tgLoader.onStart(function() {\n $(document.body).addClass(\"loader-active\");\n return $el.addClass(\"active\");\n });\n tgLoader.onEnd(function() {\n $(document.body).removeClass(\"loader-active\");\n return $el.removeClass(\"active\");\n });\n $rootscope.$on(\"$routeChangeSuccess\", function(e) {\n return tgLoader.startCurrentPageLoader();\n });\n return $rootscope.$on(\"$locationChangeSuccess\", function(e) {\n return tgLoader.reset();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLoader\", [\"tgLoader\", \"$rootScope\", LoaderDirective]);\n\n Loader = function() {\n var config, defaultConfig, forceDisabled;\n forceDisabled = false;\n defaultConfig = {\n enabled: false,\n minTime: 300\n };\n config = _.merge({}, defaultConfig);\n this.add = function() {\n return function() {\n if (!forceDisabled) {\n return config.enabled = true;\n }\n };\n };\n this.$get = [\n \"$rootScope\", function($rootscope) {\n var pageLoaded, reset, start, startLoadTime;\n startLoadTime = 0;\n reset = function() {\n return config = _.merge({}, defaultConfig);\n };\n pageLoaded = function(force) {\n var diff, endTime, timeoutValue;\n if (force == null) {\n force = false;\n }\n if (startLoadTime) {\n timeoutValue = 0;\n if (!force) {\n endTime = new Date().getTime();\n diff = endTime - startLoadTime;\n if (diff < config.minTime) {\n timeoutValue = config.minTime - diff;\n }\n }\n return timeout(timeoutValue, function() {\n return $rootscope.$broadcast(\"loader:end\");\n });\n }\n };\n start = function() {\n startLoadTime = new Date().getTime();\n return $rootscope.$broadcast(\"loader:start\");\n };\n return {\n reset: reset,\n pageLoaded: pageLoaded,\n start: start,\n startCurrentPageLoader: function() {\n if (config.enabled) {\n return start();\n }\n },\n onStart: function(fn) {\n return $rootscope.$on(\"loader:start\", fn);\n },\n onEnd: function(fn) {\n return $rootscope.$on(\"loader:end\", fn);\n },\n preventLoading: function() {\n return forceDisabled = true;\n },\n disablePreventLoading: function() {\n return forceDisabled = false;\n }\n };\n }\n ];\n };\n\n module.provider(\"tgLoader\", [Loader]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/lightboxes.coffee\n */\n\n(function() {\n var TgLoadingService, module,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n module = angular.module(\"taigaCommon\");\n\n TgLoadingService = (function(_super) {\n __extends(TgLoadingService, _super);\n\n function TgLoadingService() {\n return TgLoadingService.__super__.constructor.apply(this, arguments);\n }\n\n TgLoadingService.prototype.start = function(target) {\n if (!target.hasClass('loading')) {\n target.data('loading-old-content', target.html());\n target.addClass('loading');\n return target.html(\"\");\n }\n };\n\n TgLoadingService.prototype.finish = function(target) {\n var oldContent;\n if (target.hasClass('loading')) {\n oldContent = target.data('loading-old-content');\n target.data('loading-old-content', null);\n target.html(oldContent);\n return target.removeClass('loading');\n }\n };\n\n return TgLoadingService;\n\n })(taiga.Service);\n\n module.service(\"$tgLoading\", TgLoadingService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/popovers.coffee\n */\n\n(function() {\n var RelatedTaskStatusDirective, UsStatusDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaCommon\");\n\n UsStatusDirective = function($repo, popoverService) {\n\n /*\n Print the status of a US and a popover to change it.\n - tg-us-status: The user story\n - on-update: Method call after US is updated\n \n Example:\n \n div.status(tg-us-status=\"us\" on-update=\"ctrl.loadSprintState()\")\n a.us-status(href=\"\", title=\"Status Name\")\n \n NOTE: This directive need 'usStatusById' and 'project'.\n */\n var link, template;\n template = _.template(\"\");\n link = function($scope, $el, $attrs) {\n var $ctrl, render, us;\n $ctrl = $el.controller();\n render = function(us) {\n var usStatusById, usStatusDom, usStatusDomParent;\n usStatusDomParent = $el.find(\".us-status\");\n usStatusDom = $el.find(\".us-status .us-status-bind\");\n usStatusById = $scope.usStatusById;\n if (usStatusById[us.status]) {\n usStatusDom.text(usStatusById[us.status].name);\n return usStatusDomParent.css(\"color\", usStatusById[us.status].color);\n }\n };\n $el.on(\"click\", \".us-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", debounce(2000, function(event) {\n var target, us;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n us = $scope.$eval($attrs.tgUsStatus);\n us.status = target.data(\"status-id\");\n render(us);\n $el.find(\".pop-status\").popover().close();\n return $scope.$apply(function() {\n return $repo.save(us).then(function() {\n return $scope.$eval($attrs.onUpdate);\n });\n });\n }));\n $scope.$on(\"userstories:loaded\", function() {\n return render($scope.$eval($attrs.tgUsStatus));\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n us = $scope.$eval($attrs.tgUsStatus);\n render(us);\n return bindOnce($scope, \"project\", function(project) {\n var html;\n html = template({\n \"statuses\": project.us_statuses\n });\n $el.append(html);\n if ($scope.project.my_permissions.indexOf(\"modify_us\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUsStatus\", [\"$tgRepo\", UsStatusDirective]);\n\n RelatedTaskStatusDirective = function($repo, popoverService) {\n\n /*\n Print the status of a related task and a popover to change it.\n - tg-related-task-status: The related task\n - on-update: Method call after US is updated\n \n Example:\n \n div.status(tg-related-task-status=\"task\" on-update=\"ctrl.loadSprintState()\")\n a.task-status(href=\"\", title=\"Status Name\")\n \n NOTE: This directive need 'taskStatusById' and 'project'.\n */\n var link, selectionTemplate, updateTaskStatus;\n selectionTemplate = _.template(\"\");\n updateTaskStatus = function($el, task, taskStatusById) {\n var taskStatusDom, taskStatusDomParent;\n taskStatusDomParent = $el.find(\".us-status\");\n taskStatusDom = $el.find(\".task-status .task-status-bind\");\n if (taskStatusById[task.status]) {\n taskStatusDom.text(taskStatusById[task.status].name);\n return taskStatusDomParent.css('color', taskStatusById[task.status].color);\n }\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, autoSave, notAutoSave, task;\n $ctrl = $el.controller();\n task = $scope.$eval($attrs.tgRelatedTaskStatus);\n notAutoSave = $scope.$eval($attrs.notAutoSave);\n autoSave = !notAutoSave;\n $el.on(\"click\", \".task-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", debounce(2000, function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n task.status = target.data(\"status-id\");\n $el.find(\".pop-status\").popover().close();\n updateTaskStatus($el, task, $scope.taskStatusById);\n if (autoSave) {\n return $scope.$apply(function() {\n return $repo.save(task).then(function() {\n $scope.$eval($attrs.onUpdate);\n return $scope.$emit(\"related-tasks:status-changed\");\n });\n });\n }\n }));\n taiga.bindOnce($scope, \"project\", function(project) {\n $el.append(selectionTemplate({\n 'statuses': project.task_statuses\n }));\n updateTaskStatus($el, task, $scope.taskStatusById);\n if (project.my_permissions.indexOf(\"modify_task\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskStatus\", [\"$tgRepo\", RelatedTaskStatusDirective]);\n\n $.fn.popover = function() {\n var $el, close, closeAll, closePopover, isVisible, open;\n $el = this;\n isVisible = (function(_this) {\n return function() {\n var docViewBottom, docViewLeft, docViewRight, docViewTop, docViewWidth, elemBottom, elemLeft, elemRight, elemTop, elemWidth;\n $el.css({\n \"display\": \"block\",\n \"visibility\": \"hidden\"\n });\n docViewTop = $(window).scrollTop();\n docViewBottom = docViewTop + $(window).height();\n docViewWidth = $(window).width();\n docViewRight = docViewWidth;\n docViewLeft = 0;\n elemTop = $el.offset().top;\n elemBottom = elemTop + $el.height();\n elemWidth = $el.width();\n elemLeft = $el.offset().left;\n elemRight = $el.offset().left + elemWidth;\n $el.css({\n \"display\": \"none\",\n \"visibility\": \"visible\"\n });\n return (elemBottom <= docViewBottom) && (elemTop >= docViewTop) && (elemLeft >= docViewLeft) && (elemRight <= docViewRight);\n };\n })(this);\n closePopover = (function(_this) {\n return function(onClose) {\n if (onClose) {\n onClose.call($el);\n }\n $el.fadeOut(function() {\n return $el.removeClass(\"active\").removeClass(\"fix\");\n });\n return $el.off(\"popup:close\");\n };\n })(this);\n closeAll = (function(_this) {\n return function() {\n return $(\".popover.active\").each(function() {\n return $(this).trigger(\"popup:close\");\n });\n };\n })(this);\n open = (function(_this) {\n return function(onClose) {\n if ($el.hasClass(\"active\")) {\n return close();\n } else {\n closeAll();\n if (!isVisible()) {\n $el.addClass(\"fix\");\n }\n $el.fadeIn(function() {\n $el.addClass(\"active\");\n $(document.body).off(\"popover\");\n return $(document.body).one(\"click.popover\", function() {\n return closeAll();\n });\n });\n return $el.on(\"popup:close\", function(e) {\n return closePopover(onClose);\n });\n }\n };\n })(this);\n close = (function(_this) {\n return function() {\n return $el.trigger(\"popup:close\");\n };\n })(this);\n return {\n open: open,\n close: close,\n closeAll: closeAll\n };\n };\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/raven-logger.coffee\n */\n\n(function() {\n var ExceptionHandlerFactory, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n ExceptionHandlerFactory = function($log, config) {\n var ravenConfig;\n this.config = config;\n ravenConfig = this.config.get(\"ravenConfig\", null);\n if (ravenConfig) {\n $log.debug(\"Using the RavenJS exception handler.\");\n Raven.config(ravenConfig).install();\n return function(exception, cause) {\n $log.error.apply($log, arguments);\n return Raven.captureException(exception);\n };\n } else {\n $log.debug(\"Using the default logging exception handler.\");\n return function(exception, cause) {\n return $log.error.apply($log, arguments);\n };\n }\n };\n\n module.factory(\"$exceptionHandler\", [\"$log\", \"$tgConfig\", ExceptionHandlerFactory]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/tags.coffee\n */\n\n(function() {\n var ColorizeTagsDirective, LbTagLineDirective, TagLineDirective, TagsDirective, bindOnce, module, taiga, trim,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n TagsDirective = function() {\n var formatter, link, parser;\n formatter = function(v) {\n if (_.isArray(v)) {\n return v.join(\", \");\n }\n return \"\";\n };\n parser = function(v) {\n var result;\n if (!v) {\n return [];\n }\n result = _(v.split(\",\")).map(function(x) {\n return _.str.trim(x);\n });\n return result.value();\n };\n link = function($scope, $el, $attrs, $ctrl) {\n $ctrl.$formatters.push(formatter);\n $ctrl.$parsers.push(parser);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n require: \"ngModel\",\n link: link\n };\n };\n\n module.directive(\"tgTags\", TagsDirective);\n\n ColorizeTagsDirective = function() {\n var link, templates;\n templates = {\n backlog: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\"><%- tag.name %>\\n<% }) %>\"),\n kanban: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\" title=\\\"<%- tag.name %>\\\" />\\n<% }) %>\"),\n taskboard: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\" title=\\\"<%- tag.name %>\\\" />\\n<% }) %>\")\n };\n link = function($scope, $el, $attrs, $ctrl) {\n var render;\n render = function(srcTags) {\n var html, tags, template;\n template = templates[$attrs.tgColorizeTagsType];\n srcTags.sort();\n tags = _.map(srcTags, function(tag) {\n var color;\n color = $scope.project.tags_colors[tag];\n return {\n name: tag,\n color: color\n };\n });\n html = template({\n tags: tags\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.tgColorizeTags, function(tags) {\n if (tags != null) {\n return render(tags);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgColorizeTags\", ColorizeTagsDirective);\n\n LbTagLineDirective = function($rs) {\n var COMMA_KEY, ENTER_KEY, link, template, templateTags;\n ENTER_KEY = 13;\n COMMA_KEY = 188;\n template = \"
    \\n\\n
    \";\n templateTags = _.template(\"<% _.each(tags, function(tag) { %>\\n style=\\\"border-left: 5px solid <%- tag.color %>;\\\"<% } %>>\\n <%- tag.name %>\\n \\n \\n<% }); %>\");\n link = function($scope, $el, $attrs, $model) {\n var addValue, deleteValue, hideSaveButton, removeInputLastCharacter, renderTags, resetInput, saveInputTag, showSaveButton;\n renderTags = function(tags, tagsColors) {\n var ctx, html;\n ctx = {\n tags: _.map(tags, function(t) {\n return {\n name: t,\n color: tagsColors[t]\n };\n })\n };\n html = templateTags(ctx);\n return $el.find(\"div.tags-container\").html(html);\n };\n showSaveButton = function() {\n return $el.find(\".save\").removeClass(\"hidden\");\n };\n hideSaveButton = function() {\n return $el.find(\".save\").addClass(\"hidden\");\n };\n resetInput = function() {\n $el.find(\"input\").val(\"\");\n return $el.find(\"input\").autocomplete(\"close\");\n };\n addValue = function(value) {\n var tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue, false);\n if (tags == null) {\n tags = [];\n }\n if (__indexOf.call(tags, value) < 0) {\n tags.push(value);\n }\n return $scope.$apply(function() {\n return $model.$setViewValue(tags);\n });\n };\n deleteValue = function(value) {\n var tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue, false);\n tags = _.pull(tags, value);\n return $scope.$apply(function() {\n return $model.$setViewValue(tags);\n });\n };\n saveInputTag = function() {\n var value;\n value = $el.find(\"input\").val();\n addValue(value);\n resetInput();\n return hideSaveButton();\n };\n removeInputLastCharacter = (function(_this) {\n return function(input) {\n var inputValue;\n inputValue = input.val();\n return input.val(inputValue.substring(0, inputValue.length - 1));\n };\n })(this);\n $el.on(\"keypress\", \"input\", function(event) {\n if (event.keyCode !== ENTER_KEY) {\n return;\n }\n return event.preventDefault();\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n if (event.keyCode === ENTER_KEY) {\n return saveInputTag();\n } else if (event.keyCode === COMMA_KEY) {\n removeInputLastCharacter(target);\n return saveInputTag();\n } else {\n if (target.val().length) {\n return showSaveButton();\n } else {\n return hideSaveButton();\n }\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n event.preventDefault();\n return saveInputTag();\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var target, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.siblings(\".tag-name\").text();\n return deleteValue(value);\n });\n bindOnce($scope, \"project\", function(project) {\n var positioningFunction;\n positioningFunction = function(position, elements) {\n var menu;\n menu = elements.element.element;\n menu.css(\"width\", elements.target.width);\n menu.css(\"top\", position.top);\n return menu.css(\"left\", position.left);\n };\n return $el.find(\"input\").autocomplete({\n source: _.keys(project.tags_colors),\n position: {\n my: \"left top\",\n using: positioningFunction\n },\n select: function(event, ui) {\n addValue(ui.item.value);\n return ui.item.value = \"\";\n }\n });\n });\n $scope.$watch($attrs.ngModel, function(tags) {\n var tagsColors, _ref;\n tagsColors = ((_ref = $scope.project) != null ? _ref.tags_colors : void 0) || [];\n return renderTags(tags, tagsColors);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgLbTagLine\", [\"$tgResources\", LbTagLineDirective]);\n\n TagLineDirective = function($rootScope, $repo, $rs, $confirm, $qqueue) {\n var COMMA_KEY, ENTER_KEY, ESC_KEY, link, template, templateTags;\n ENTER_KEY = 13;\n ESC_KEY = 27;\n COMMA_KEY = 188;\n template = \"
    \\n\\n \\n Add tag\\n\\n\\n\";\n templateTags = _.template(\"<% _.each(tags, function(tag) { %>\\n ;\\\">\\n <%- tag.name %>\\n <% if (isEditable) { %>\\n \\n <% } %>\\n \\n<% }); %>\");\n link = function($scope, $el, $attrs, $model) {\n var addValue, deleteValue, hideAddTagButton, hideAddTagButtonText, hideInput, hideSaveButton, isEditable, removeInputLastCharacter, renderInReadModeOnly, renderTags, resetInput, saveInputTag, showAddTagButton, showAddTagButtonText, showInput, showSaveButton;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n renderTags = function(tags, tagsColors) {\n var ctx, html;\n ctx = {\n tags: _.map(tags, function(t) {\n return {\n name: t,\n color: tagsColors[t]\n };\n }),\n isEditable: isEditable()\n };\n html = templateTags(ctx);\n return $el.find(\"div.tags-container\").html(html);\n };\n renderInReadModeOnly = function() {\n $el.find(\".add-tag\").remove();\n $el.find(\"input\").remove();\n return $el.find(\".save\").remove();\n };\n showAddTagButton = function() {\n return $el.find(\".add-tag\").removeClass(\"hidden\");\n };\n hideAddTagButton = function() {\n return $el.find(\".add-tag\").addClass(\"hidden\");\n };\n showAddTagButtonText = function() {\n return $el.find(\".add-tag-text\").removeClass(\"hidden\");\n };\n hideAddTagButtonText = function() {\n return $el.find(\".add-tag-text\").addClass(\"hidden\");\n };\n showSaveButton = function() {\n return $el.find(\".save\").removeClass(\"hidden\");\n };\n hideSaveButton = function() {\n return $el.find(\".save\").addClass(\"hidden\");\n };\n showInput = function() {\n return $el.find(\"input\").removeClass(\"hidden\").focus();\n };\n hideInput = function() {\n return $el.find(\"input\").addClass(\"hidden\").blur();\n };\n resetInput = function() {\n $el.find(\"input\").val(\"\");\n return $el.find(\"input\").autocomplete(\"close\");\n };\n addValue = $qqueue.bindAdd(function(value) {\n var model, onError, onSuccess, tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue.tags, false);\n if (tags == null) {\n tags = [];\n }\n if (__indexOf.call(tags, value) < 0) {\n tags.push(value);\n }\n model = $model.$modelValue.clone();\n model.tags = tags;\n $model.$setViewValue(model);\n onSuccess = function() {\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n model.revert();\n return $model.$setViewValue(model);\n };\n return $repo.save(model).then(onSuccess, onError);\n });\n deleteValue = $qqueue.bindAdd(function(value) {\n var model, onError, onSuccess, tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue.tags, false);\n tags = _.pull(tags, value);\n model = $model.$modelValue.clone();\n model.tags = tags;\n $model.$setViewValue(model);\n onSuccess = function() {\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n model.revert();\n return $model.$setViewValue(model);\n };\n return $repo.save(model).then(onSuccess, onError);\n });\n saveInputTag = function() {\n var value;\n value = $el.find(\"input\").val();\n addValue(value);\n resetInput();\n return hideSaveButton();\n };\n removeInputLastCharacter = (function(_this) {\n return function(input) {\n var inputValue;\n inputValue = input.val();\n return input.val(inputValue.substring(0, inputValue.length - 1));\n };\n })(this);\n $el.on(\"keypress\", \"input\", function(event) {\n var _ref;\n if ((_ref = event.keyCode) !== ENTER_KEY && _ref !== ESC_KEY) {\n return;\n }\n return event.preventDefault();\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n if (event.keyCode === ENTER_KEY) {\n return saveInputTag();\n } else if (event.keyCode === COMMA_KEY) {\n removeInputLastCharacter(target);\n return saveInputTag();\n } else if (event.keyCode === ESC_KEY) {\n resetInput();\n hideInput();\n hideSaveButton();\n return showAddTagButton();\n } else {\n if (target.val().length) {\n return showSaveButton();\n } else {\n return hideSaveButton();\n }\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n event.preventDefault();\n return saveInputTag();\n });\n $el.on(\"click\", \".add-tag\", function(event) {\n event.preventDefault();\n hideAddTagButton();\n return showInput();\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var target, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.siblings(\".tag-name\").text();\n return deleteValue(value);\n });\n bindOnce($scope, \"project\", function(project) {\n var positioningFunction;\n if (!isEditable()) {\n renderInReadModeOnly();\n return;\n }\n showAddTagButton();\n positioningFunction = function(position, elements) {\n var menu;\n menu = elements.element.element;\n menu.css(\"width\", elements.target.width);\n menu.css(\"top\", position.top);\n return menu.css(\"left\", position.left);\n };\n return $el.find(\"input\").autocomplete({\n source: _.keys(project.tags_colors),\n position: {\n my: \"left top\",\n using: positioningFunction\n },\n select: function(event, ui) {\n addValue(ui.item.value);\n return ui.item.value = \"\";\n }\n });\n });\n $scope.$watch($attrs.ngModel, function(model) {\n var tagsColors, _ref, _ref1;\n if (!model) {\n return;\n }\n if ((_ref = model.tags) != null ? _ref.length : void 0) {\n hideAddTagButtonText();\n } else {\n showAddTagButtonText();\n }\n tagsColors = ((_ref1 = $scope.project) != null ? _ref1.tags_colors : void 0) || [];\n return renderTags(model.tags, tagsColors);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgTagLine\", [\"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$tgQqueue\", TagLineDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/wisiwyg.coffee\n */\n\n(function() {\n var bindOnce, module, taiga, tgMarkitupDirective;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n tgMarkitupDirective = function($rootscope, $rs, $tr, $selectedText) {\n var link, previewTemplate;\n previewTemplate = _.template(\"
    \\n
    \\n \\n
    \\n
    \\n <%= data %>\\n
    \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var closePreviewMode, element, markdownCaretPositon, markdownSettings, markdownTitle, preview, previewDomNode, removeEmptyLine, setCaretPosition;\n element = angular.element($el);\n previewDomNode = $(\"
    \", {\n \"class\": \"preview\"\n });\n closePreviewMode = function() {\n element.parents(\".markdown\").find(\".preview\").remove();\n return element.parents(\".markItUp\").show();\n };\n $scope.$on(\"markdown-editor:submit\", function() {\n return closePreviewMode();\n });\n preview = function() {\n var markItUpDomNode, markdownDomNode;\n markdownDomNode = element.parents(\".markdown\");\n markItUpDomNode = element.parents(\".markItUp\");\n return $rs.mdrender.render($scope.projectId, $model.$modelValue).then(function(data) {\n var markdown;\n markdownDomNode.append(previewTemplate({\n data: data.data\n }));\n markItUpDomNode.hide();\n markdown = element.closest(\".markdown\");\n return markdown.on(\"mouseup.preview\", \".preview\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.target);\n if (!target.is('a') && $selectedText.get().length) {\n return;\n }\n markdown.off(\".preview\");\n return closePreviewMode();\n });\n });\n };\n markdownCaretPositon = false;\n setCaretPosition = function(elm, caretPos) {\n var range;\n if (elm.createTextRange) {\n range = elm.createTextRange();\n range.move(\"character\", caretPos);\n return range.select();\n } else if (elm.selectionStart) {\n elm.focus();\n return elm.setSelectionRange(caretPos, caretPos);\n }\n };\n removeEmptyLine = function(textarea, line, currentCaretPosition) {\n var lines, removedLineLength;\n lines = textarea.value.split(\"\\n\");\n removedLineLength = lines[line].length;\n lines[line] = \"\";\n textarea.value = lines.join(\"\\n\");\n return currentCaretPosition - removedLineLength + 1;\n };\n markdownSettings = {\n nameSpace: \"markdown\",\n onShiftEnter: {\n keepDefault: false,\n openWith: \"\\n\\n\"\n },\n onEnter: {\n keepDefault: false,\n replaceWith: (function(_this) {\n return function(data) {\n var breakLineAtBeginning, cursorLine, emptyListItem, lastLine, lines, match, newLineContent;\n lines = data.textarea.value.split(\"\\n\");\n cursorLine = data.textarea.value.slice(0, +(data.caretPosition - 1) + 1 || 9e9).split(\"\\n\").length;\n newLineContent = data.textarea.value.slice(data.caretPosition).split(\"\\n\")[0];\n lastLine = lines[cursorLine - 1];\n match = lastLine.match(/^(\\s*- ).*/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*)\\-\\s$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)\\-\\s/);\n if (!breakLineAtBeginning) {\n if (match) {\n return \"\\n\" + match[1];\n }\n }\n }\n }\n match = lastLine.match(/^(\\s*\\* ).*/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*\\* )$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)\\*\\s/);\n if (!breakLineAtBeginning) {\n if (match) {\n return \"\\n\" + match[1];\n }\n }\n }\n }\n match = lastLine.match(/^(\\s*)(\\d+)\\.\\s/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*)(\\d+)\\.\\s$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)(\\d+)\\.\\s/);\n if (!breakLineAtBeginning) {\n return \"\\n\" + (match[1] + (parseInt(match[2], 10) + 1)) + \". \";\n }\n }\n }\n return \"\\n\";\n };\n })(this),\n afterInsert: function(data) {\n var caretPosition, line, scrollRelation, totalLines;\n if (markdownCaretPositon) {\n setCaretPosition(data.textarea, markdownCaretPositon);\n caretPosition = markdownCaretPositon;\n markdownCaretPositon = false;\n } else {\n caretPosition = data.caretPosition;\n }\n totalLines = data.textarea.value.split(\"\\n\").length;\n line = data.textarea.value.slice(0, +(caretPosition - 1) + 1 || 9e9).split(\"\\n\").length;\n scrollRelation = line / totalLines;\n return $el.scrollTop((scrollRelation * $el[0].scrollHeight) - ($el.height() / 2));\n }\n },\n markupSet: [\n {\n name: $tr.t(\"markdown-editor.heading-1\"),\n key: \"1\",\n placeHolder: $tr.t(\"markdown-editor.placeholder\"),\n closeWith: function(markItUp) {\n return markdownTitle(markItUp, \"=\");\n }\n }, {\n name: $tr.t(\"markdown-editor.heading-2\"),\n key: \"2\",\n placeHolder: $tr.t(\"markdown-editor.placeholder\"),\n closeWith: function(markItUp) {\n return markdownTitle(markItUp, \"-\");\n }\n }, {\n name: $tr.t(\"markdown-editor.heading-3\"),\n key: \"3\",\n openWith: \"### \",\n placeHolder: $tr.t(\"markdown-editor.placeholder\")\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.bold\"),\n key: \"B\",\n openWith: \"**\",\n closeWith: \"**\"\n }, {\n name: $tr.t(\"markdown-editor.italic\"),\n key: \"I\",\n openWith: \"_\",\n closeWith: \"_\"\n }, {\n name: $tr.t(\"markdown-editor.strike\"),\n key: \"S\",\n openWith: \"~~\",\n closeWith: \"~~\"\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.bulleted-list\"),\n openWith: \"- \"\n }, {\n name: $tr.t(\"markdown-editor.numeric-list\"),\n openWith: function(markItUp) {\n return markItUp.line + \". \";\n }\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.picture\"),\n key: \"P\",\n replaceWith: '![[![Alternative text]!]]([![Url:!:http://]!] \"[![Title]!]\")'\n }, {\n name: $tr.t(\"markdown-editor.link\"),\n key: \"L\",\n openWith: \"[\",\n closeWith: ']([![Url:!:http://]!] \"[![Title]!]\")',\n placeHolder: $tr.t(\"markdown-editor.link-placeholder\")\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.quotes\"),\n openWith: \"> \"\n }, {\n name: $tr.t(\"markdown-editor.code-block\"),\n openWith: \"```\\n\",\n closeWith: \"\\n```\"\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.preview\"),\n call: preview,\n className: \"preview-icon\"\n }\n ],\n afterInsert: function(event) {\n var target;\n target = angular.element(event.textarea);\n return $model.$setViewValue(target.val());\n }\n };\n markdownTitle = function(markItUp, char) {\n var heading, i, n, _i, _ref;\n heading = \"\";\n n = $.trim(markItUp.selection || markItUp.placeHolder).length;\n for (i = _i = 0, _ref = n - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {\n heading += char;\n }\n return \"\\n\" + heading + \"\\n\";\n };\n element.markItUp(markdownSettings);\n element.on(\"keypress\", function(event) {\n return $scope.$apply();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgMarkitup\", [\"$rootScope\", \"$tgResources\", \"$tgI18n\", \"$selectedText\", tgMarkitupDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/main.coffee\n */\n\n(function() {\n var BacklogFiltersDirective, bindOnce, debounceLeading, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n debounceLeading = this.taiga.debounceLeading;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogFiltersDirective = function($log, $location) {\n var link, template, templateSelected;\n template = _.template(\"<% _.each(filters, function(f) { %>\\n <% if (f.selected) { %>\\n \\\"\\n data-id=\\\"<%- f.id %>\\\">\\n style=\\\"border-left: 3px solid <%- f.color %>;\\\"<% } %>>\\n <%- f.name %>\\n \\n <%- f.count %>\\n \\n <% } else { %>\\n \\\"\\n data-id=\\\"<%- f.id %>\\\">\\n style=\\\"border-left: 3px solid <%- f.color %>;\\\"<% } %>>\\n <%- f.name %>\\n \\n <%- f.count %>\\n \\n <% } %>\\n<% }) %>\");\n templateSelected = _.template(\"<% _.each(filters, function(f) { %>\\n\\\"\\n data-id=\\\"<%- f.id %>\\\">\\n style=\\\"border-left: 3px solid <%- f.color %>;\\\"<% } %>>\\n <%- f.name %>\\n \\n\\n<% }) %>\");\n link = function($scope, $el, $attrs) {\n var $ctrl, initializeSelectedFilters, renderFilters, renderSelectedFilters, selectQFilter, selectedFilters, showCategories, showFilters, toggleFilterSelection;\n $ctrl = $el.closest(\".wrapper\").controller();\n selectedFilters = [];\n showFilters = function(title, type) {\n $el.find(\".filters-cats\").hide();\n $el.find(\".filter-list\").removeClass(\"hidden\");\n $el.find(\"h2.breadcrumb\").removeClass(\"hidden\");\n $el.find(\"h2 a.subfilter span.title\").html(title);\n return $el.find(\"h2 a.subfilter span.title\").prop(\"data-type\", type);\n };\n showCategories = function() {\n $el.find(\".filters-cats\").show();\n $el.find(\".filter-list\").addClass(\"hidden\");\n return $el.find(\"h2.breadcrumb\").addClass(\"hidden\");\n };\n initializeSelectedFilters = function(filters) {\n var name, val, values, _i, _len;\n showCategories();\n selectedFilters = [];\n for (name in filters) {\n values = filters[name];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n val = values[_i];\n if (val.selected) {\n selectedFilters.push(val);\n }\n }\n }\n return renderSelectedFilters();\n };\n renderSelectedFilters = function() {\n var html;\n html = templateSelected({\n filters: selectedFilters\n });\n return $el.find(\".filters-applied\").html(html);\n };\n renderFilters = function(filters) {\n var html;\n html = template({\n filters: filters\n });\n return $el.find(\".filter-list\").html(html);\n };\n toggleFilterSelection = function(type, id) {\n var currentFiltersType, filter, filters;\n filters = $scope.filters[type];\n filter = _.find(filters, {\n id: taiga.toString(id)\n });\n filter.selected = !filter.selected;\n if (filter.selected) {\n selectedFilters.push(filter);\n $scope.$apply(function() {\n $ctrl.selectFilter(type, id);\n return $ctrl.filterVisibleUserstories();\n });\n } else {\n selectedFilters = _.reject(selectedFilters, filter);\n $scope.$apply(function() {\n $ctrl.unselectFilter(type, id);\n return $ctrl.filterVisibleUserstories();\n });\n }\n renderSelectedFilters(selectedFilters);\n currentFiltersType = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (type === currentFiltersType) {\n renderFilters(_.reject(filters, \"selected\"));\n }\n return $ctrl.loadUserstories();\n };\n selectQFilter = debounceLeading(100, function(value) {\n if (value === void 0) {\n return;\n }\n if (value.length === 0) {\n $ctrl.replaceFilter(\"q\", null);\n } else {\n $ctrl.replaceFilter(\"q\", value);\n }\n return $ctrl.loadUserstories();\n });\n $scope.$watch(\"filtersQ\", selectQFilter);\n $scope.$on(\"filters:loaded\", function(ctx, filters) {\n return initializeSelectedFilters(filters);\n });\n $el.on(\"click\", \".filters-cats > ul > li > a\", function(event) {\n var tags, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n tags = $scope.filters[target.data(\"type\")];\n renderFilters(_.reject(tags, \"selected\"));\n return showFilters(target.attr(\"title\"), target.data(\"type\"));\n });\n $el.on(\"click\", \".filters-inner > .filters-step-cat > .breadcrumb > .back\", function(event) {\n event.preventDefault();\n return showCategories();\n });\n $el.on(\"click\", \".filters-applied a\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n id = target.data(\"id\");\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n return $el.on(\"click\", \".filter-list .single-filter\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n if (target.hasClass(\"active\")) {\n target.removeClass(\"active\");\n } else {\n target.addClass(\"active\");\n }\n id = target.data(\"id\");\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogFilters\", [\"$log\", \"$tgLocation\", BacklogFiltersDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/lightboxes.coffee\n */\n\n(function() {\n var CreateEditSprint, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaBacklog\");\n\n CreateEditSprint = function($repo, $confirm, $rs, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var createSprint, hasErrors, remove, submit, submitButton;\n hasErrors = false;\n createSprint = true;\n $scope.sprint = {\n project: null,\n name: null,\n estimated_start: null,\n estimated_finish: null\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, newSprint, promise, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n hasErrors = true;\n $el.find(\".last-sprint-name\").addClass(\"disappear\");\n return;\n }\n hasErrors = false;\n newSprint = angular.copy($scope.sprint);\n broadcastEvent = null;\n if (createSprint) {\n newSprint.estimated_start = moment(newSprint.estimated_start).format(\"YYYY-MM-DD\");\n newSprint.estimated_finish = moment(newSprint.estimated_finish).format(\"YYYY-MM-DD\");\n promise = $repo.create(\"milestones\", newSprint);\n broadcastEvent = \"sprintform:create:success\";\n } else {\n newSprint.setAttr(\"estimated_start\", moment(newSprint.estimated_start).format(\"YYYY-MM-DD\"));\n newSprint.setAttr(\"estimated_finish\", moment(newSprint.estimated_finish).format(\"YYYY-MM-DD\"));\n promise = $repo.save(newSprint);\n broadcastEvent = \"sprintform:edit:success\";\n }\n $loading.start(submitButton);\n promise.then(function(data) {\n $loading.finish(submitButton);\n if (createSprint) {\n $scope.sprintsCounter += 1;\n }\n $rootscope.$broadcast(broadcastEvent, data);\n return lightboxService.close($el);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"light-error\", data._error_message);\n } else if (data.__all__) {\n return $confirm.notify(\"light-error\", data.__all__[0]);\n }\n });\n };\n })(this));\n remove = function() {\n var message, title;\n title = \"Delete sprint\";\n message = $scope.sprint.name;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n finish();\n $scope.milestonesCounter -= 1;\n lightboxService.close($el);\n return $rootscope.$broadcast(\"sprintform:remove:success\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\");\n };\n return $repo.remove($scope.sprint).then(onSuccess, onError);\n };\n })(this));\n };\n $scope.$on(\"sprintform:create\", function(event, projectId) {\n var estimatedFinish, estimatedStart, lastSprint, lastSprintNameDom;\n createSprint = true;\n $scope.sprint.project = projectId;\n $scope.sprint.name = null;\n $scope.sprint.slug = null;\n lastSprint = $scope.sprints[0];\n estimatedStart = moment();\n if ($scope.sprint.estimated_start) {\n estimatedStart = moment($scope.sprint.estimated_start);\n } else if (lastSprint != null) {\n estimatedStart = moment(lastSprint.estimated_finish);\n }\n $scope.sprint.estimated_start = estimatedStart.format(\"DD MMM YYYY\");\n estimatedFinish = moment().add(2, \"weeks\");\n if ($scope.sprint.estimated_finish) {\n estimatedFinish = moment($scope.sprint.estimated_finish);\n } else if (lastSprint != null) {\n estimatedFinish = moment(lastSprint.estimated_finish).add(2, \"weeks\");\n }\n $scope.sprint.estimated_finish = estimatedFinish.format(\"DD MMM YYYY\");\n lastSprintNameDom = $el.find(\".last-sprint-name\");\n if ((lastSprint != null ? lastSprint.name : void 0) != null) {\n lastSprintNameDom.html(\" last sprint is \" + lastSprint.name + \" ;-) \");\n }\n $el.find(\".delete-sprint\").addClass(\"hidden\");\n $el.find(\".title\").text(\"New sprint\");\n $el.find(\".button-green\").text(\"Create\");\n lightboxService.open($el);\n return $el.find(\".sprint-name\").focus();\n });\n $scope.$on(\"sprintform:edit\", function(ctx, sprint) {\n createSprint = false;\n $scope.$apply(function() {\n $scope.sprint = sprint;\n $scope.sprint.estimated_start = moment($scope.sprint.estimated_start).format(\"DD MMM YYYY\");\n return $scope.sprint.estimated_finish = moment($scope.sprint.estimated_finish).format(\"DD MMM YYYY\");\n });\n $el.find(\".delete-sprint\").removeClass(\"hidden\");\n $el.find(\".title\").text(\"Edit sprint\");\n $el.find(\".button-green\").text(\"Save\");\n lightboxService.open($el);\n $el.find(\".sprint-name\").focus().select();\n return $el.find(\".last-sprint-name\").addClass(\"disappear\");\n });\n $el.on(\"keyup\", \".sprint-name\", function(event) {\n if ($el.find(\".sprint-name\").val().length > 0 || hasErrors) {\n return $el.find(\".last-sprint-name\").addClass(\"disappear\");\n } else {\n return $el.find(\".last-sprint-name\").removeClass(\"disappear\");\n }\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $el.on(\"click\", \".delete-sprint .icon-delete\", function(event) {\n event.preventDefault();\n return remove();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateEditSprint\", [\"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateEditSprint]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/main.coffee\n */\n\n(function() {\n var BacklogController, BacklogDirective, TgBacklogProgressBarDirective, UsPointsDirective, UsRolePointsSelectorDirective, bindMethods, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, tgBacklogGraphDirective, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogController = (function(_super) {\n __extends(BacklogController, _super);\n\n BacklogController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function BacklogController(scope, rootscope, repo, confirm, rs, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Backlog\";\n this.showTags = false;\n this.activeFilters = false;\n this.excludeClosedSprints = true;\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(\"Backlog - \" + _this.scope.project.name);\n if (_this.rs.userstories.getShowTags(_this.scope.projectId)) {\n _this.showTags = true;\n return _this.scope.$broadcast(\"showTags\", _this.showTags);\n }\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n BacklogController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"usform:bulk:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"bulk create userstory on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"sprintform:create:success\", (function(_this) {\n return function() {\n _this.loadSprints();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"sprint\", \"create\", \"create sprint on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"usform:new:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"create userstory on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"sprintform:edit:success\", (function(_this) {\n return function() {\n return _this.loadProjectStats();\n };\n })(this));\n this.scope.$on(\"sprintform:remove:success\", (function(_this) {\n return function() {\n _this.loadSprints();\n _this.loadProjectStats();\n return _this.loadUserstories();\n };\n })(this));\n this.scope.$on(\"usform:edit:success\", (function(_this) {\n return function() {\n return _this.loadUserstories();\n };\n })(this));\n this.scope.$on(\"sprint:us:move\", this.moveUs);\n this.scope.$on(\"sprint:us:moved\", this.loadSprints);\n this.scope.$on(\"sprint:us:moved\", this.loadProjectStats);\n return this.scope.$on(\"backlog:toggle-closed-sprints-visualization\", this.toggleClosedSprintsVisualization);\n };\n\n BacklogController.prototype.initializeSubscription = function() {\n var routingKey1, routingKey2;\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n _this.loadUserstories();\n return _this.loadSprints();\n };\n })(this));\n routingKey2 = \"changes.project.\" + this.scope.projectId + \".milestones\";\n return this.events.subscribe(this.scope, routingKey2, (function(_this) {\n return function(message) {\n return _this.loadSprints();\n };\n })(this));\n };\n\n BacklogController.prototype.toggleShowTags = function() {\n return this.scope.$apply((function(_this) {\n return function() {\n _this.showTags = !_this.showTags;\n return _this.rs.userstories.storeShowTags(_this.scope.projectId, _this.showTags);\n };\n })(this));\n };\n\n BacklogController.prototype.toggleActiveFilters = function() {\n return this.activeFilters = !this.activeFilters;\n };\n\n BacklogController.prototype.loadProjectStats = function() {\n return this.rs.projects.stats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n _this.scope.stats = stats;\n if (stats.total_points) {\n _this.scope.stats.completedPercentage = Math.round(100 * stats.closed_points / stats.total_points);\n } else {\n _this.scope.stats.completedPercentage = 0;\n }\n return stats;\n };\n })(this));\n };\n\n BacklogController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n BacklogController.prototype.loadSprints = function() {\n var params;\n params = {};\n if (this.excludeClosedSprints) {\n params[\"closed\"] = false;\n }\n return this.rs.sprints.list(this.scope.projectId, params).then((function(_this) {\n return function(sprints) {\n var sprint, _i, _len;\n for (_i = 0, _len = sprints.length; _i < _len; _i++) {\n sprint = sprints[_i];\n sprint.user_stories = _.sortBy(sprint.user_stories, \"sprint_order\");\n }\n _this.scope.sprints = sprints;\n _this.scope.openSprints = _.filter(sprints, function(sprint) {\n return !sprint.closed;\n }).reverse();\n _this.scope.closedSprints = _.filter(sprints, function(sprint) {\n return sprint.closed;\n });\n if (!_this.excludeClosedSprints) {\n _this.scope.totalClosedMilestones = _this.scope.closedSprints.length;\n }\n _this.scope.sprintsCounter = sprints.length;\n _this.scope.sprintsById = groupBy(sprints, function(x) {\n return x.id;\n });\n _this.rootscope.$broadcast(\"sprints:loaded\", sprints);\n return sprints;\n };\n })(this));\n };\n\n BacklogController.prototype.resetFilters = function() {\n var selectedStatuses, selectedTags;\n selectedTags = _.filter(this.scope.filters.tags, \"selected\");\n selectedStatuses = _.filter(this.scope.filters.statuses, \"selected\");\n this.scope.filtersQ = \"\";\n _.each([selectedTags, selectedStatuses], (function(_this) {\n return function(filterGrp) {\n return _.each(filterGrp, function(item) {\n var filter, filters;\n filters = _this.scope.filters[item.type];\n filter = _.find(filters, {\n id: taiga.toString(item.id)\n });\n filter.selected = false;\n return _this.unselectFilter(item.type, item.id);\n });\n };\n })(this));\n return this.loadUserstories();\n };\n\n BacklogController.prototype.loadUserstories = function() {\n var promise;\n this.scope.httpParams = this.getUrlFilters();\n this.rs.userstories.storeQueryParams(this.scope.projectId, this.scope.httpParams);\n promise = this.q.all([this.refreshTagsColors(), this.rs.userstories.listUnassigned(this.scope.projectId, this.scope.httpParams)]);\n return promise.then((function(_this) {\n return function(data) {\n var userstories;\n userstories = data[1];\n _this.scope.userstories = _.sortBy(userstories, \"backlog_order\");\n _this.generateFilters();\n _this.filterVisibleUserstories();\n _this.rootscope.$broadcast(\"filters:loaded\", _this.scope.filters);\n scopeDefer(_this.scope, function() {\n return _this.scope.$broadcast(\"userstories:loaded\");\n });\n return userstories;\n };\n })(this));\n };\n\n BacklogController.prototype.loadBacklog = function() {\n return this.q.all([this.loadProjectStats(), this.loadSprints(), this.loadUserstories()]);\n };\n\n BacklogController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.totalClosedMilestones = project.total_closed_milestones;\n _this.scope.$emit('project:loaded', project);\n _this.scope.points = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(x) {\n return x.id;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"id\");\n return project;\n };\n })(this));\n };\n\n BacklogController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.initializeSubscription();\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadBacklog();\n };\n })(this));\n };\n\n BacklogController.prototype.toggleClosedSprintsVisualization = function() {\n this.excludeClosedSprints = !this.excludeClosedSprints;\n return this.loadSprints();\n };\n\n BacklogController.prototype.filterVisibleUserstories = function() {\n var selectedStatuses, selectedTags;\n this.scope.visibleUserstories = [];\n selectedTags = _.filter(this.scope.filters.tags, \"selected\");\n selectedTags = _.map(selectedTags, \"name\");\n if (selectedTags.length === 0) {\n this.scope.visibleUserstories = _.clone(this.scope.userstories, false);\n } else {\n this.scope.visibleUserstories = _.reject(this.scope.userstories, (function(_this) {\n return function(us) {\n if (_.intersection(selectedTags, us.tags).length === 0) {\n return true;\n }\n return false;\n };\n })(this));\n }\n selectedStatuses = _.filter(this.scope.filters.statuses, \"selected\");\n selectedStatuses = _.map(selectedStatuses, \"id\");\n if (selectedStatuses.length > 0) {\n this.scope.visibleUserstories = _.reject(this.scope.visibleUserstories, (function(_this) {\n return function(us) {\n var res;\n res = _.find(selectedStatuses, function(x) {\n return x === taiga.toString(us.status);\n });\n return !res;\n };\n })(this));\n }\n return this.rs.userstories.storeQueryParams(this.scope.projectId, {\n \"status\": selectedStatuses,\n \"tags\": selectedTags,\n \"project\": this.scope.projectId,\n \"milestone\": null\n });\n };\n\n BacklogController.prototype.prepareBulkUpdateData = function(uses, field) {\n if (field == null) {\n field = \"backlog_order\";\n }\n return _.map(uses, function(x) {\n return {\n \"us_id\": x.id,\n \"order\": x[field]\n };\n });\n };\n\n BacklogController.prototype.resortUserStories = function(uses, field) {\n var index, item, items, _i, _len;\n if (field == null) {\n field = \"backlog_order\";\n }\n items = [];\n for (index = _i = 0, _len = uses.length; _i < _len; index = ++_i) {\n item = uses[index];\n item[field] = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n BacklogController.prototype.moveUs = function(ctx, usList, newUsIndex, newSprintId) {\n var data, items, newSprint, oldSprintId, project, promise, promises, us, userstories, _i, _j, _k, _len, _len1, _len2;\n oldSprintId = usList[0].milestone;\n project = usList[0].project;\n if (newSprintId === oldSprintId) {\n items = null;\n userstories = null;\n if (newSprintId === null) {\n userstories = this.scope.userstories;\n } else {\n userstories = this.scope.sprintsById[newSprintId].user_stories;\n }\n this.scope.$apply(function() {\n var args, key, r, us, _i, _len;\n for (key = _i = 0, _len = usList.length; _i < _len; key = ++_i) {\n us = usList[key];\n r = userstories.indexOf(us);\n userstories.splice(r, 1);\n }\n args = [newUsIndex, 0].concat(usList);\n return Array.prototype.splice.apply(userstories, args);\n });\n if (newSprintId === null) {\n items = this.resortUserStories(userstories, \"backlog_order\");\n data = this.prepareBulkUpdateData(items, \"backlog_order\");\n this.rs.userstories.bulkUpdateBacklogOrder(project, data).then((function(_this) {\n return function() {\n var us, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n };\n })(this));\n } else {\n items = this.resortUserStories(userstories, \"sprint_order\");\n data = this.prepareBulkUpdateData(items, \"sprint_order\");\n this.rs.userstories.bulkUpdateSprintOrder(project, data).then((function(_this) {\n return function() {\n var us, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n };\n })(this));\n }\n return promise;\n }\n if (newSprintId === null) {\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n us.milestone = null;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, key, r, sprint, _j, _len1, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(_this.scope.userstories, args);\n Array.prototype.splice.apply(_this.scope.visibleUserstories, args);\n _this.filterVisibleUserstories();\n sprint = _this.scope.sprintsById[oldSprintId];\n _results = [];\n for (key = _j = 0, _len1 = usList.length; _j < _len1; key = ++_j) {\n us = usList[key];\n r = sprint.user_stories.indexOf(us);\n _results.push(sprint.user_stories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n promise = this.repo.save(us);\n promise = promise.then((function(_this) {\n return function() {\n items = _this.resortUserStories(_this.scope.userstories, \"backlog_order\");\n data = _this.prepareBulkUpdateData(items, \"backlog_order\");\n return _this.rs.userstories.bulkUpdateBacklogOrder(us.project, data).then(function() {\n return _this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId);\n });\n };\n })(this));\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n return promise;\n }\n newSprint = this.scope.sprintsById[newSprintId];\n if (oldSprintId === null) {\n for (_j = 0, _len1 = usList.length; _j < _len1; _j++) {\n us = usList[_j];\n us.milestone = newSprintId;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, key, r, _k, _len2, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(newSprint.user_stories, args);\n _results = [];\n for (key = _k = 0, _len2 = usList.length; _k < _len2; key = ++_k) {\n us = usList[key];\n r = _this.scope.visibleUserstories.indexOf(us);\n _this.scope.visibleUserstories.splice(r, 1);\n r = _this.scope.userstories.indexOf(us);\n _results.push(_this.scope.userstories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n } else {\n for (_k = 0, _len2 = usList.length; _k < _len2; _k++) {\n us = usList[_k];\n us.milestone = newSprintId;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, oldSprint, r, _l, _len3, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(newSprint.user_stories, args);\n _results = [];\n for (_l = 0, _len3 = usList.length; _l < _len3; _l++) {\n us = usList[_l];\n oldSprint = _this.scope.sprintsById[oldSprintId];\n r = oldSprint.user_stories.indexOf(us);\n _results.push(oldSprint.user_stories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n }\n promises = _.map(usList, (function(_this) {\n return function(us) {\n return _this.repo.save(us);\n };\n })(this));\n promise = this.q.all(promises).then((function(_this) {\n return function() {\n items = _this.resortUserStories(newSprint.user_stories, \"sprint_order\");\n data = _this.prepareBulkUpdateData(items, \"sprint_order\");\n _this.rs.userstories.bulkUpdateSprintOrder(project, data).then(function() {\n return _this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId);\n });\n return _this.rs.userstories.bulkUpdateBacklogOrder(project, data).then(function() {\n var _l, _len3, _results;\n _results = [];\n for (_l = 0, _len3 = usList.length; _l < _len3; _l++) {\n us = usList[_l];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n });\n };\n })(this));\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n return promise;\n };\n\n BacklogController.prototype.getUrlFilters = function() {\n return _.pick(this.location.search(), \"statuses\", \"tags\", \"q\");\n };\n\n BacklogController.prototype.generateFilters = function() {\n var isSelected, name, plainStatuses, plainTags, searchdata, urlfilters, val, value, _i, _len, _ref;\n urlfilters = this.getUrlFilters();\n if (urlfilters.q) {\n this.scope.filtersQ = urlfilters.q;\n }\n searchdata = {};\n for (name in urlfilters) {\n value = urlfilters[name];\n if (searchdata[name] == null) {\n searchdata[name] = {};\n }\n _ref = taiga.toString(value).split(\",\");\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n val = _ref[_i];\n searchdata[name][val] = true;\n }\n }\n isSelected = function(type, id) {\n if ((searchdata[type] != null) && searchdata[type][id]) {\n return true;\n }\n return false;\n };\n this.scope.filters = {};\n plainTags = _.flatten(_.filter(_.map(this.scope.userstories, \"tags\")));\n plainTags.sort();\n this.scope.filters.tags = _.map(_.countBy(plainTags), (function(_this) {\n return function(v, k) {\n var obj;\n obj = {\n id: k,\n type: \"tags\",\n name: k,\n color: _this.scope.project.tags_colors[k],\n count: v\n };\n if (isSelected(\"tags\", obj.id)) {\n obj.selected = true;\n }\n return obj;\n };\n })(this));\n plainStatuses = _.map(this.scope.userstories, \"status\");\n plainStatuses = _.filter(plainStatuses, (function(_this) {\n return function(status) {\n if (status) {\n return status;\n }\n };\n })(this));\n this.scope.filters.statuses = _.map(_.countBy(plainStatuses), (function(_this) {\n return function(v, k) {\n var obj;\n obj = {\n id: k,\n type: \"statuses\",\n name: _this.scope.usStatusById[k].name,\n color: _this.scope.usStatusById[k].color,\n count: v\n };\n if (isSelected(\"statuses\", obj.id)) {\n obj.selected = true;\n }\n return obj;\n };\n })(this));\n return this.scope.filters;\n };\n\n BacklogController.prototype.editUserStory = function(us) {\n return this.rootscope.$broadcast(\"usform:edit\", us);\n };\n\n BacklogController.prototype.deleteUserStory = function(us) {\n var message, title;\n title = \"Delete User Story\";\n message = us.subject;\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var promise;\n _this.scope.userstories = _.without(_this.scope.userstories, us);\n _this.filterVisibleUserstories();\n promise = _this.repo.remove(us);\n promise.then(function() {\n finish();\n return _this.loadBacklog();\n });\n return promise.then(null, function() {\n finish(false);\n return _this.confirm.notify(\"error\");\n });\n };\n })(this));\n };\n\n BacklogController.prototype.addNewUs = function(type) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"usform:new\", this.scope.projectId, this.scope.project.default_us_status, this.scope.usStatusList);\n case \"bulk\":\n return this.rootscope.$broadcast(\"usform:bulk\", this.scope.projectId, this.scope.project.default_us_status);\n }\n };\n\n BacklogController.prototype.addNewSprint = function() {\n return this.rootscope.$broadcast(\"sprintform:create\", this.scope.projectId);\n };\n\n return BacklogController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"BacklogController\", BacklogController);\n\n BacklogDirective = function($repo, $rootscope) {\n var doomLineTemplate, link, linkDoomLine, linkFilters, linkToolbar, showHideFilter, showHideTags;\n doomLineTemplate = _.template(\"
    Project Scope [Doomline]
    \");\n linkDoomLine = function($scope, $el, $attrs, $ctrl) {\n var addDoomLineDom, getUsItems, reloadDoomLine, removeDoomlineDom;\n reloadDoomLine = function() {\n var current_sum, element, elements, scope, stats, total_points, _i, _len, _results;\n if ($scope.stats != null) {\n removeDoomlineDom();\n elements = getUsItems();\n stats = $scope.stats;\n total_points = stats.total_points;\n current_sum = stats.assigned_points;\n _results = [];\n for (_i = 0, _len = elements.length; _i < _len; _i++) {\n element = elements[_i];\n scope = element.scope();\n if (scope.us == null) {\n continue;\n }\n current_sum += scope.us.total_points;\n if (current_sum > total_points) {\n addDoomLineDom(element);\n break;\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n }\n };\n removeDoomlineDom = function() {\n return $el.find(\".doom-line\").remove();\n };\n addDoomLineDom = function(element) {\n return element != null ? element.before(doomLineTemplate({})) : void 0;\n };\n getUsItems = function() {\n var rowElements;\n rowElements = $el.find('.backlog-table-body .us-item-row');\n return _.map(rowElements, function(x) {\n return angular.element(x);\n });\n };\n $scope.$on(\"userstories:loaded\", reloadDoomLine);\n return $scope.$watch(\"stats\", reloadDoomLine);\n };\n linkToolbar = function($scope, $el, $attrs, $ctrl) {\n var moveToCurrentSprint;\n moveToCurrentSprint = function(selectedUss) {\n var extraPoints, totalExtraPoints, ussCurrent;\n ussCurrent = _($scope.userstories);\n $scope.userstories = ussCurrent.without.apply(ussCurrent, selectedUss).value();\n extraPoints = _.map(selectedUss, function(v, k) {\n return v.total_points;\n });\n totalExtraPoints = _.reduce(extraPoints, function(acc, num) {\n return acc + num;\n });\n $scope.sprints[0].user_stories = _.union($scope.sprints[0].user_stories, selectedUss);\n $scope.sprints[0].total_points += totalExtraPoints;\n $ctrl.filterVisibleUserstories();\n return $repo.saveAll(selectedUss).then(function() {\n $ctrl.loadSprints();\n return $ctrl.loadProjectStats();\n });\n };\n $el.on(\"change\", \".backlog-table-body .user-stories input:checkbox\", function(event) {\n var moveToCurrentSprintDom, selectedUsDom, target;\n target = angular.element(event.currentTarget);\n moveToCurrentSprintDom = $el.find(\"#move-to-current-sprint\");\n selectedUsDom = $el.find(\".backlog-table-body .user-stories input:checkbox:checked\");\n if (selectedUsDom.length > 0 && $scope.sprints.length > 0) {\n moveToCurrentSprintDom.show();\n } else {\n moveToCurrentSprintDom.hide();\n }\n return target.closest('.us-item-row').toggleClass('ui-multisortable-multiple');\n });\n $el.on(\"click\", \"#move-to-current-sprint\", (function(_this) {\n return function(event) {\n var ussDom, ussToMove;\n ussDom = $el.find(\".backlog-table-body .user-stories input:checkbox:checked\");\n ussToMove = _.map(ussDom, function(item) {\n var itemScope;\n itemScope = angular.element(item).scope();\n itemScope.us.milestone = $scope.sprints[0].id;\n return itemScope.us;\n });\n return $scope.$apply(_.partial(moveToCurrentSprint, ussToMove));\n };\n })(this));\n return $el.on(\"click\", \"#show-tags\", function(event) {\n event.preventDefault();\n $ctrl.toggleShowTags();\n return showHideTags($ctrl);\n });\n };\n showHideTags = function($ctrl) {\n var elm;\n elm = angular.element(\"#show-tags\");\n if ($ctrl.showTags) {\n elm.addClass(\"active\");\n return elm.find(\".text\").text(\"Hide Tags\");\n } else {\n elm.removeClass(\"active\");\n return elm.find(\".text\").text(\"Show Tags\");\n }\n };\n showHideFilter = function($scope, $el, $ctrl) {\n var sidebar, target;\n sidebar = $el.find(\"sidebar.filters-bar\");\n sidebar.one(\"transitionend\", function() {\n return timeout(150, function() {\n $rootscope.$broadcast(\"resize\");\n return $('.burndown').css(\"visibility\", \"visible\");\n });\n });\n target = angular.element(\"#show-filters-button\");\n $('.burndown').css(\"visibility\", \"hidden\");\n sidebar.toggleClass(\"active\");\n target.toggleClass(\"active\");\n toggleText(target.find(\".text\"), [\"Remove Filters\", \"Show Filters\"]);\n if (!sidebar.hasClass(\"active\")) {\n $ctrl.resetFilters();\n }\n return $ctrl.toggleActiveFilters();\n };\n linkFilters = function($scope, $el, $attrs, $ctrl) {\n $scope.filtersSearch = {};\n return $el.on(\"click\", \"#show-filters-button\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n return showHideFilter($scope, $el, $ctrl);\n });\n });\n };\n link = function($scope, $el, $attrs, $rootscope) {\n var $ctrl, filters;\n $ctrl = $el.controller();\n linkToolbar($scope, $el, $attrs, $ctrl);\n linkFilters($scope, $el, $attrs, $ctrl);\n linkDoomLine($scope, $el, $attrs, $ctrl);\n $el.find(\".backlog-table-body\").disableSelection();\n filters = $ctrl.getUrlFilters();\n if (filters.statuses || filters.tags || filters.q) {\n showHideFilter($scope, $el, $ctrl);\n }\n $scope.$on(\"showTags\", function() {\n return showHideTags($ctrl);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklog\", [\"$tgRepo\", \"$rootScope\", BacklogDirective]);\n\n UsRolePointsSelectorDirective = function($rootscope) {\n var link, selectionTemplate;\n selectionTemplate = _.template(\"\");\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var numberOfRoles, roles;\n roles = _.filter(project.roles, \"computable\");\n numberOfRoles = _.size(roles);\n if (numberOfRoles > 1) {\n return $el.append(selectionTemplate({\n \"roles\": roles\n }));\n } else {\n $el.find(\".icon-arrow-bottom\").remove();\n return $el.find(\".header-points\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"uspoints:select\", function(ctx, roleId, roleName) {\n $el.find(\".popover\").popover().close();\n return $el.find(\".header-points\").html(\"\" + roleName + \"/Total\");\n });\n $scope.$on(\"uspoints:clear-selection\", function(ctx, roleId) {\n $el.find(\".popover\").popover().close();\n return $el.find(\".header-points\").text(\"Points\");\n });\n $el.on(\"click\", function(event) {\n var target;\n target = angular.element(event.target);\n if (target.is(\"span\") || target.is(\"div\")) {\n event.stopPropagation();\n }\n return $el.find(\".popover\").popover().open();\n });\n $el.on(\"click\", \".clear-selection\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $rootscope.$broadcast(\"uspoints:clear-selection\");\n });\n $el.on(\"click\", \".role\", function(event) {\n var rolScope, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n rolScope = target.scope();\n return $rootscope.$broadcast(\"uspoints:select\", target.data(\"role-id\"), target.text());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUsRolePointsSelector\", [\"$rootScope\", UsRolePointsSelectorDirective]);\n\n UsPointsDirective = function($repo) {\n var link, pointsTemplate, rolesTemplate;\n rolesTemplate = _.template(\"\");\n pointsTemplate = _.template(\"\");\n link = function($scope, $el, $attrs) {\n var $ctrl, calculateTotalPoints, computableRoles, numberOfRoles, renderPoints, renderPointsSelector, renderRolesSelector, roles, selectedRoleId, updatePointsRoles, updatingSelectedRoleId, us;\n $ctrl = $el.controller();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = null;\n selectedRoleId = null;\n numberOfRoles = _.size(us.points);\n if (numberOfRoles === 1) {\n selectedRoleId = _.keys(us.points)[0];\n }\n roles = [];\n updatePointsRoles = function() {\n return roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = us.points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = pointObj.value != null ? pointObj.value : \"?\";\n return role;\n });\n };\n computableRoles = _.filter($scope.project.roles, \"computable\");\n updatePointsRoles();\n if (roles.length === 0) {\n $el.find(\".icon-arrow-bottom\").remove();\n $el.find(\"a.us-points\").addClass(\"not-clickable\");\n }\n renderPointsSelector = function(us, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = us.points[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n $el.append(html);\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n return $el.find(\".pop-points-open\").popover().open();\n };\n renderRolesSelector = function(us) {\n var html;\n updatePointsRoles();\n html = rolesTemplate({\n \"roles\": roles\n });\n $el.append(html);\n return $el.find(\".pop-role\").popover().open(function() {\n return $(this).remove();\n });\n };\n renderPoints = function(us, roleId) {\n var dom, pointId, pointObj, totalPoints;\n dom = $el.find(\"a > span.points-value\");\n if (roleId === null || numberOfRoles === 1) {\n totalPoints = us.total_points != null ? us.total_points : \"?\";\n dom.text(totalPoints);\n return dom.parent().prop(\"title\", totalPoints);\n } else {\n pointId = us.points[roleId];\n pointObj = $scope.pointsById[pointId];\n dom.html(\"\" + pointObj.name + \" / \" + us.total_points + \"\");\n return dom.parent().prop(\"title\", \"\" + pointObj.name + \" / \" + us.total_points);\n }\n };\n calculateTotalPoints = function() {\n var values;\n values = _.map(us.points, function(v, k) {\n return $scope.pointsById[v].value;\n });\n values = _.filter(values, function(num) {\n return num != null;\n });\n if (values.length === 0) {\n return \"?\";\n }\n return _.reduce(values, function(acc, num) {\n return acc + num;\n });\n };\n $scope.$watch($attrs.tgBacklogUsPoints, function(us) {\n if (us) {\n return renderPoints(us, selectedRoleId);\n }\n });\n $scope.$on(\"uspoints:select\", function(ctx, roleId, roleName) {\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n renderPoints(us, roleId);\n return selectedRoleId = roleId;\n });\n $scope.$on(\"uspoints:clear-selection\", function(ctx) {\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n renderPoints(us, null);\n return selectedRoleId = null;\n });\n if (roles.length > 0) {\n $el.on(\"click\", \"a.us-points span\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = selectedRoleId;\n if (selectedRoleId != null) {\n return renderPointsSelector(us, selectedRoleId);\n } else {\n return renderRolesSelector(us);\n }\n });\n $el.on(\"click\", \".role\", function(event) {\n var popRolesDom, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = target.data(\"role-id\");\n popRolesDom = $el.find(\".pop-role\");\n popRolesDom.find(\"a\").removeClass(\"active\");\n popRolesDom.find(\"a[data-role-id='\" + updatingSelectedRoleId + \"']\").addClass(\"active\");\n return renderPointsSelector(us, updatingSelectedRoleId);\n });\n $el.on(\"click\", \".point\", function(event) {\n var points, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n $el.find(\".pop-points-open\").hide();\n $el.find(\".pop-role\").hide();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n points = _.clone(us.points, true);\n points[updatingSelectedRoleId] = target.data(\"point-id\");\n return $scope.$apply(function() {\n us.points = points;\n us.total_points = calculateTotalPoints(us);\n renderPoints(us, selectedRoleId);\n return $repo.save(us).then(function() {\n return $repo.refresh(us).then(function() {\n return $ctrl.loadProjectStats();\n });\n });\n });\n });\n }\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogUsPoints\", [\"$tgRepo\", UsPointsDirective]);\n\n tgBacklogGraphDirective = function() {\n var link, redrawChart;\n redrawChart = function(element, dataToDraw) {\n var client_increment_line, colors, data, evolution_line, milestonesRange, optimal_line, options, team_increment_line, width, zero_line, _i, _ref, _results;\n width = element.width();\n element.height(width / 6);\n milestonesRange = (function() {\n _results = [];\n for (var _i = 0, _ref = dataToDraw.milestones.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }\n return _results;\n }).apply(this);\n data = [];\n zero_line = _.map(dataToDraw.milestones, function(ml) {\n return 0;\n });\n data.push({\n data: _.zip(milestonesRange, zero_line),\n lines: {\n fillColor: \"rgba(0,0,0,0)\"\n },\n points: {\n show: false\n }\n });\n optimal_line = _.map(dataToDraw.milestones, function(ml) {\n return ml.optimal;\n });\n data.push({\n data: _.zip(milestonesRange, optimal_line),\n lines: {\n fillColor: \"rgba(120,120,120,0.2)\"\n }\n });\n evolution_line = _.filter(_.map(dataToDraw.milestones, function(ml) {\n return ml.evolution;\n }), function(evolution) {\n return evolution != null;\n });\n data.push({\n data: _.zip(milestonesRange, evolution_line),\n lines: {\n fillColor: \"rgba(102,153,51,0.3)\"\n }\n });\n team_increment_line = _.map(dataToDraw.milestones, function(ml) {\n return -ml[\"team-increment\"];\n });\n data.push({\n data: _.zip(milestonesRange, team_increment_line),\n lines: {\n fillColor: \"rgba(153,51,51,0.3)\"\n }\n });\n client_increment_line = _.map(dataToDraw.milestones, function(ml) {\n return -ml[\"team-increment\"] - ml[\"client-increment\"];\n });\n data.push({\n data: _.zip(milestonesRange, client_increment_line),\n lines: {\n fillColor: \"rgba(255,51,51,0.3)\"\n }\n });\n colors = [\"rgba(0,0,0,1)\", \"rgba(120,120,120,0.2)\", \"rgba(102,153,51,1)\", \"rgba(153,51,51,1)\", \"rgba(255,51,51,1)\"];\n options = {\n grid: {\n borderWidth: {\n top: 0,\n right: 1,\n left: 0,\n bottom: 0\n },\n borderColor: \"#ccc\",\n hoverable: true\n },\n xaxis: {\n ticks: dataToDraw.milestones.length,\n axisLabel: \"Sprints\",\n axisLabelUseCanvas: true,\n axisLabelFontSizePixels: 14,\n axisLabelFontFamily: \"Verdana, Arial, Helvetica, Tahoma, sans-serif\",\n axisLabelPadding: 15,\n tickFormatter: function(val, axis) {\n return \"\";\n }\n },\n series: {\n shadowSize: 0,\n lines: {\n show: true,\n fill: true\n },\n points: {\n show: true,\n fill: true,\n radius: 4,\n lineWidth: 2\n }\n },\n colors: colors,\n tooltip: true,\n tooltipOpts: {\n content: function(label, xval, yval, flotItem) {\n if (flotItem.seriesIndex === 1) {\n return \"Optimal pending points for sprint \" + xval + \" should be \" + yval;\n } else if (flotItem.seriesIndex === 2) {\n return \"Real pending points for sprint \" + xval + \" is \" + yval;\n } else if (flotItem.seriesIndex === 3) {\n return \"Incremented points by team requirements for sprint \" + xval + \" is \" + (Math.abs(yval));\n } else {\n return \"Incremented points by client requirements for sprint \" + xval + \" is \" + (Math.abs(yval));\n }\n }\n }\n };\n element.empty();\n return element.plot(data, options).data(\"plot\");\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch(\"stats\", function(value) {\n if ($scope.stats != null) {\n redrawChart(element, $scope.stats);\n return $scope.$on(\"resize\", function() {\n return redrawChart(element, $scope.stats);\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGmBacklogGraph\", tgBacklogGraphDirective);\n\n TgBacklogProgressBarDirective = function() {\n var adjustPercentaje, link, render, template;\n template = _.template(\"
    \\n
    %\\\">
    \\n
    %\\\">
    \");\n render = function(el, projectPointsPercentaje, closedPointsPercentaje) {\n return el.html(template({\n projectPointsPercentaje: projectPointsPercentaje,\n closedPointsPercentaje: closedPointsPercentaje\n }));\n };\n adjustPercentaje = function(percentage) {\n var adjusted;\n adjusted = _.max([0, percentage]);\n adjusted = _.min([100, adjusted]);\n return Math.round(adjusted);\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch($attrs.tgBacklogProgressBar, function(stats) {\n var closedPoints, closedPointsPercentaje, definedPoints, projectPointsPercentaje, totalPoints;\n if (stats != null) {\n totalPoints = stats.total_points;\n definedPoints = stats.defined_points;\n closedPoints = stats.closed_points;\n if (definedPoints > totalPoints) {\n projectPointsPercentaje = totalPoints * 100 / definedPoints;\n closedPointsPercentaje = closedPoints * 100 / definedPoints;\n } else {\n projectPointsPercentaje = 100;\n closedPointsPercentaje = closedPoints * 100 / totalPoints;\n }\n projectPointsPercentaje = adjustPercentaje(projectPointsPercentaje - 3);\n closedPointsPercentaje = adjustPercentaje(closedPointsPercentaje - 3);\n return render($el, projectPointsPercentaje, closedPointsPercentaje);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogProgressBar\", TgBacklogProgressBarDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/sortable.coffee\n */\n\n(function() {\n var BacklogEmptySortableDirective, BacklogSortableDirective, SprintSortableDirective, bindOnce, deleteElement, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaBacklog\");\n\n deleteElement = function(el) {\n el.scope().$destroy();\n el.off();\n return el.remove();\n };\n\n BacklogSortableDirective = function($repo, $rs, $rootscope, $tgConfirm) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var filterError;\n if (!(project.my_permissions.indexOf(\"modify_us\") > -1)) {\n return;\n }\n filterError = function() {\n return $tgConfirm.notify(\"error\", \"You can't drop on backlog when filters are open\");\n };\n $el.sortable({\n connectWith: \".sprint\",\n containment: \".wrapper\",\n dropOnEmpty: true,\n placeholder: \"row us-item-row us-item-drag sortable-placeholder\",\n scroll: true,\n tolerance: \"pointer\",\n revert: false,\n cursorAt: {\n right: 15\n },\n stop: function() {\n if ($el.hasClass(\"active-filters\")) {\n $el.sortable(\"cancel\");\n return filterError();\n }\n }\n });\n $el.on(\"multiplesortreceive\", function(event, ui) {\n var itemIndex, itemUs;\n if ($el.hasClass(\"active-filters\")) {\n ui.source.sortable(\"cancel\");\n filterError();\n return;\n }\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n deleteElement(ui.item);\n $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, null);\n return ui.item.find('a').removeClass('noclick');\n });\n $el.on(\"multiplesortstop\", function(event, ui) {\n var index, items, us;\n if ($(ui.items[0]).parent().length === 0) {\n return;\n }\n items = _.sortBy(ui.items, function(item) {\n return $(item).index();\n });\n index = _.min(_.map(items, function(item) {\n return $(item).index();\n }));\n us = _.map(items, function(item) {\n var itemUs;\n item = $(item);\n itemUs = item.scope().us;\n setTimeout(((function(_this) {\n return function() {\n return item.find('a').removeClass('noclick');\n };\n })(this)), 300);\n return itemUs;\n });\n return $scope.$emit(\"sprint:us:move\", us, index, null);\n });\n return $el.on(\"sortstart\", function(event, ui) {\n return ui.item.find('a').addClass('noclick');\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n BacklogEmptySortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n $el.sortable({\n dropOnEmpty: true\n });\n return $el.on(\"sortreceive\", function(event, ui) {\n var itemIndex, itemUs;\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n deleteElement(ui.item);\n $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, null);\n return ui.item.find('a').removeClass('noclick');\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n SprintSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n $el.sortable({\n scroll: true,\n dropOnEmpty: true,\n items: \".sprint-table .milestone-us-item-row\",\n connectWith: \".sprint,.backlog-table-body,.empty-backlog\"\n });\n $el.on(\"multiplesortreceive\", function(event, ui) {\n var index, items, us;\n items = _.sortBy(ui.items, function(item) {\n return $(item).index();\n });\n index = _.min(_.map(items, function(item) {\n return $(item).index();\n }));\n us = _.map(items, function(item) {\n var itemUs;\n item = $(item);\n itemUs = item.scope().us;\n deleteElement(item);\n return itemUs;\n });\n return $scope.$emit(\"sprint:us:move\", us, index, $scope.sprint.id);\n });\n $el.on(\"multiplesortstop\", function(event, ui) {\n var itemIndex, itemUs;\n if (ui.item.parent().length === 0) {\n return;\n }\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n setTimeout(((function(_this) {\n return function() {\n return ui.item.find('a').removeClass('noclick');\n };\n })(this)), 300);\n return $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, $scope.sprint.id);\n });\n return $el.on(\"sortstart\", function(event, ui) {\n return ui.item.find('a').addClass('noclick');\n });\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"$tgConfirm\", BacklogSortableDirective]);\n\n module.directive(\"tgBacklogEmptySortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", BacklogEmptySortableDirective]);\n\n module.directive(\"tgSprintSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", SprintSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/sprints.coffee\n */\n\n(function() {\n var BacklogSprintDirective, BacklogSprintHeaderDirective, ToggleExcludeClosedSprintsVisualization, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogSprintDirective = function($repo, $rootscope) {\n var link, refreshSprintTableHeight, slideOptions, sprintTableMinHeight, toggleSprint;\n sprintTableMinHeight = 50;\n slideOptions = {\n duration: 500,\n easing: 'linear'\n };\n refreshSprintTableHeight = (function(_this) {\n return function(sprintTable) {\n if (!sprintTable.find(\".row\").length) {\n return sprintTable.css(\"height\", sprintTableMinHeight);\n } else {\n return sprintTable.css(\"height\", \"auto\");\n }\n };\n })(this);\n toggleSprint = (function(_this) {\n return function($el) {\n var sprintArrow, sprintTable;\n sprintTable = $el.find(\".sprint-table\");\n sprintArrow = $el.find(\".icon-arrow-up\");\n sprintArrow.toggleClass('active');\n sprintTable.toggleClass('open');\n return refreshSprintTableHeight(sprintTable);\n };\n })(this);\n link = function($scope, $el, $attrs) {\n $scope.$watch($attrs.tgBacklogSprint, function(sprint) {\n sprint = $scope.$eval($attrs.tgBacklogSprint);\n if ($scope.$first) {\n return toggleSprint($el);\n } else if (sprint.closed) {\n return $el.addClass(\"sprint-closed\");\n } else if (!$scope.$first && !sprint.closed) {\n toggleSprint($el);\n return $el.addClass(\"sprint-old-open\");\n }\n });\n $el.on(\"click\", \".sprint-name > .icon-arrow-up\", function(event) {\n toggleSprint($el);\n return $el.find(\".sprint-table\").slideToggle(slideOptions);\n });\n $el.on(\"click\", \".sprint-name > .icon-edit\", function(event) {\n var sprint;\n sprint = $scope.$eval($attrs.tgBacklogSprint);\n return $rootscope.$broadcast(\"sprintform:edit\", sprint);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogSprint\", [\"$tgRepo\", \"$rootScope\", BacklogSprintDirective]);\n\n BacklogSprintHeaderDirective = function($navUrls) {\n var link, template;\n template = _.template(\"
    \\n \\n\\n <% if(isVisible){ %>\\n \\\" title=\\\"'Go to the taskboard of '<%- name %>'\\\">\\n <%- name %>\\n \\n <% } %>\\n\\n <% if(isEditable){ %>\\n \\n <% } %>\\n
    \\n\\n
    \\n
    <%- estimatedDateRange %>
    \\n
      \\n
    • \\n <%- closedPoints %>\\n closed\\n
    • \\n
    • \\n <%- totalPoints %>\\n total\\n
    • \\n
    \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, isVisible, render;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_milestone\") !== -1;\n };\n isVisible = function() {\n return $scope.project.my_permissions.indexOf(\"view_milestones\") !== -1;\n };\n render = function(sprint) {\n var ctx, estimatedDateRange, finish, start, taskboardUrl;\n taskboardUrl = $navUrls.resolve(\"project-taskboard\", {\n project: $scope.project.slug,\n sprint: sprint.slug\n });\n start = moment(sprint.estimated_start).format(\"DD MMM YYYY\");\n finish = moment(sprint.estimated_finish).format(\"DD MMM YYYY\");\n estimatedDateRange = \"\" + start + \"-\" + finish;\n ctx = {\n name: sprint.name,\n taskboardUrl: taskboardUrl,\n estimatedDateRange: estimatedDateRange,\n closedPoints: sprint.closed_points || 0,\n totalPoints: sprint.total_points || 0,\n isVisible: isVisible(),\n isEditable: isEditable()\n };\n return $el.html(template(ctx));\n };\n $scope.$watch($attrs.ngModel, function(sprint) {\n return render(sprint);\n });\n $scope.$on(\"sprintform:edit:success\", function() {\n return render($model.$modelValue);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgBacklogSprintHeader\", [\"$tgNavUrls\", \"$tgRepo\", \"$rootScope\", BacklogSprintHeaderDirective]);\n\n ToggleExcludeClosedSprintsVisualization = function($rootscope, $loading) {\n var excludeClosedSprints, link;\n excludeClosedSprints = false;\n link = function($scope, $el, $attrs) {\n $el.on(\"click\", \"\", function(event) {\n $loading.start($el.siblings('.load'));\n return $rootscope.$broadcast(\"backlog:toggle-closed-sprints-visualization\");\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return $scope.$on(\"sprints:loaded\", (function(_this) {\n return function(ctx, sprints) {\n var closedSprints;\n closedSprints = _.filter(sprints, function(sprint) {\n return sprint.closed;\n });\n $loading.finish($el.siblings('.load'));\n if (closedSprints.length > 0) {\n return $el.text(\"Hide closed sprints\");\n } else {\n return $el.text(\"Show closed sprints\");\n }\n };\n })(this));\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogToggleClosedSprintsVisualization\", [\"$rootScope\", \"$tgLoading\", ToggleExcludeClosedSprintsVisualization]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/charts.coffee\n */\n\n(function() {\n var SprintGraphDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaTaskboard\");\n\n SprintGraphDirective = function() {\n var link, redrawChart;\n redrawChart = function(element, dataToDraw) {\n var data, days, options, width;\n width = element.width();\n element.height(240);\n days = _.map(dataToDraw, function(x) {\n return moment(x.day);\n });\n data = [];\n data.unshift({\n data: _.zip(days, _.map(dataToDraw, function(d) {\n return d.optimal_points;\n })),\n lines: {\n fillColor: \"rgba(120,120,120,0.2)\"\n }\n });\n data.unshift({\n data: _.zip(days, _.map(dataToDraw, function(d) {\n return d.open_points;\n })),\n lines: {\n fillColor: \"rgba(102,153,51,0.3)\"\n }\n });\n options = {\n grid: {\n borderWidth: {\n top: 0,\n right: 1,\n left: 0,\n bottom: 0\n },\n borderColor: '#ccc',\n hoverable: true\n },\n xaxis: {\n tickSize: [1, \"day\"],\n min: days[0],\n max: _.last(days),\n mode: \"time\",\n daysNames: days,\n axisLabel: 'Day',\n axisLabelUseCanvas: true,\n axisLabelFontSizePixels: 12,\n axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',\n axisLabelPadding: 5\n },\n yaxis: {\n min: 0\n },\n series: {\n shadowSize: 0,\n lines: {\n show: true,\n fill: true\n },\n points: {\n show: true,\n fill: true,\n radius: 4,\n lineWidth: 2\n }\n },\n colors: [\"rgba(102,153,51,1)\", \"rgba(120,120,120,0.2)\"],\n tooltip: true,\n tooltipOpts: {\n content: function(label, xval, yval, flotItem) {\n var formattedDate, roundedValue;\n formattedDate = moment(xval).format(\"DD MMM\");\n roundedValue = Math.round(yval);\n if (flotItem.seriesIndex === 1) {\n return \"Optimal pending points for day \" + formattedDate + \" should be \" + roundedValue;\n } else {\n return \"Real pending points for day \" + formattedDate + \" is \" + roundedValue;\n }\n }\n }\n };\n element.empty();\n return element.plot(data, options).data(\"plot\");\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$on(\"resize\", function() {\n if ($scope.stats) {\n return redrawChart(element, $scope.stats.days);\n }\n });\n $scope.$on(\"taskboard:graph:toggle-visibility\", function() {\n $el.parent().toggleClass('open');\n return timeout(100, function() {\n if ($scope.stats) {\n return redrawChart(element, $scope.stats.days);\n }\n });\n });\n $scope.$watch('stats', function(value) {\n if ($scope.stats == null) {\n return;\n }\n return redrawChart(element, $scope.stats.days);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSprintGraph\", SprintGraphDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/lightboxes.coffee\n */\n\n(function() {\n var CreateBulkTasksDirective, CreateEditTaskDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n CreateEditTaskDirective = function($repo, $model, $rs, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.isNew = true;\n $scope.$on(\"taskform:new\", function(ctx, sprintId, usId) {\n $scope.task = {\n project: $scope.projectId,\n milestone: sprintId,\n user_story: usId,\n is_archived: false,\n status: $scope.project.default_task_status,\n assigned_to: null,\n tags: []\n };\n $scope.isNew = true;\n $el.find(\".button-green span\").html(\"Create\");\n $el.find(\".title\").html(\"New task \");\n $el.find(\".tag-input\").val(\"\");\n return lightboxService.open($el);\n });\n $scope.$on(\"taskform:edit\", function(ctx, task) {\n $scope.task = task;\n $scope.isNew = false;\n $el.find(\".button-green span\").html(\"Save\");\n $el.find(\".title\").html(\"Edit task \");\n $el.find(\".tag-input\").val(\"\");\n return lightboxService.open($el);\n });\n submitButton = $el.find(\".submit-button\");\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n if ($scope.isNew) {\n promise = $repo.create(\"tasks\", $scope.task);\n broadcastEvent = \"taskform:new:success\";\n } else {\n promise = $repo.save($scope.task);\n broadcastEvent = \"taskform:edit:success\";\n }\n $loading.start(submitButton);\n return promise.then(function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n return $rootscope.$broadcast(broadcastEvent, data);\n });\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n CreateBulkTasksDirective = function($repo, $rs, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.form = {\n data: \"\",\n usId: null\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, projectId, promise, sprintId, usId;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n data = $scope.form.data;\n projectId = $scope.projectId;\n sprintId = $scope.form.sprintId;\n usId = $scope.form.usId;\n promise = $rs.tasks.bulkCreate(projectId, sprintId, usId, data);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"taskform:bulk:success\", result);\n return lightboxService.close($el);\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return console.log(\"FAIL\");\n });\n };\n })(this));\n $scope.$on(\"taskform:bulk\", function(ctx, sprintId, usId) {\n lightboxService.open($el);\n return $scope.form = {\n data: \"\",\n sprintId: sprintId,\n usId: usId\n };\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaTaskboard\");\n\n module.directive(\"tgLbCreateEditTask\", [\"$tgRepo\", \"$tgModel\", \"$tgResources\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateEditTaskDirective]);\n\n module.directive(\"tgLbCreateBulkTasks\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateBulkTasksDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard.coffee\n */\n\n(function() {\n var TaskboardController, TaskboardDirective, TaskboardSquishColumnDirective, TaskboardTableHeightFixerDirective, TaskboardTaskDirective, TaskboardUserDirective, bindMethods, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n toggleText = this.taiga.toggleText;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n scopeDefer = this.taiga.scopeDefer;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaTaskboard\");\n\n TaskboardController = (function(_super) {\n __extends(TaskboardController, _super);\n\n TaskboardController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$appTitle\", \"$tgLocation\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function TaskboardController(scope, rootscope, repo, confirm, rs, params, q, appTitle, location, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.appTitle = appTitle;\n this.location = location;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Taskboard\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Taskboard - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TaskboardController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"taskform:bulk:success\", (function(_this) {\n return function() {\n _this.loadTaskboard();\n return _this.analytics.trackEvent(\"task\", \"create\", \"bulk create task on taskboard\", 1);\n };\n })(this));\n this.scope.$on(\"taskform:new:success\", (function(_this) {\n return function() {\n _this.loadTaskboard();\n return _this.analytics.trackEvent(\"task\", \"create\", \"create task on taskboard\", 1);\n };\n })(this));\n this.scope.$on(\"taskform:edit:success\", (function(_this) {\n return function() {\n return _this.loadTaskboard();\n };\n })(this));\n this.scope.$on(\"taskboard:task:move\", this.taskMove);\n return this.scope.$on(\"assigned-to:added\", (function(_this) {\n return function(ctx, userId, task) {\n var promise;\n task.assigned_to = userId;\n promise = _this.repo.save(task);\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n })(this));\n };\n\n TaskboardController.prototype.initializeSubscription = function() {\n var routingKey, routingKey1;\n routingKey = \"changes.project.\" + this.scope.projectId + \".tasks\";\n this.events.subscribe(this.scope, routingKey, (function(_this) {\n return function(message) {\n return _this.loadTaskboard();\n };\n })(this));\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n return this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n _this.refreshTagsColors();\n _this.loadSprintStats();\n return _this.loadSprint();\n };\n })(this));\n };\n\n TaskboardController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(e) {\n return e.id;\n });\n _this.scope.roleById = groupBy(project.roles, function(e) {\n return e.id;\n });\n _this.scope.taskStatusList = _.sortBy(project.task_statuses, \"order\");\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.scope.usStatusById = groupBy(project.us_statuses, function(e) {\n return e.id;\n });\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadSprintStats = function() {\n return this.rs.sprints.stats(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(stats) {\n var completedPointsSum, remainingPointsSum, remainingTasks, totalPointsSum;\n totalPointsSum = _.reduce(_.values(stats.total_points), (function(res, n) {\n return res + n;\n }), 0);\n completedPointsSum = _.reduce(_.values(stats.completed_points), (function(res, n) {\n return res + n;\n }), 0);\n remainingPointsSum = totalPointsSum - completedPointsSum;\n remainingTasks = stats.total_tasks - stats.completed_tasks;\n _this.scope.stats = stats;\n _this.scope.stats.totalPointsSum = totalPointsSum;\n _this.scope.stats.completedPointsSum = completedPointsSum;\n _this.scope.stats.remainingPointsSum = remainingPointsSum;\n _this.scope.stats.remainingTasks = remainingTasks;\n if (stats.totalPointsSum) {\n _this.scope.stats.completedPercentage = Math.round(100 * stats.completedPointsSum / stats.totalPointsSum);\n } else {\n _this.scope.stats.completedPercentage = 0;\n }\n _this.scope.stats.openTasks = stats.total_tasks - stats.completed_tasks;\n return stats;\n };\n })(this));\n };\n\n TaskboardController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadSprint = function() {\n return this.rs.sprints.get(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n _this.scope.userstories = _.sortBy(sprint.user_stories, \"sprint_order\");\n return sprint;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadTasks = function() {\n return this.rs.tasks.list(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(tasks) {\n var status, task, us, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;\n _this.scope.tasks = _.sortBy(tasks, 'taskboard_order');\n _this.scope.usTasks = {};\n _ref = _.union(_this.scope.userstories, [\n {\n id: null\n }\n ]);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n us = _ref[_i];\n _this.scope.usTasks[us.id] = {};\n _ref1 = _this.scope.taskStatusList;\n for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n status = _ref1[_j];\n _this.scope.usTasks[us.id][status.id] = [];\n }\n }\n _ref2 = _this.scope.tasks;\n for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n task = _ref2[_k];\n if ((_this.scope.usTasks[task.user_story] != null) && (_this.scope.usTasks[task.user_story][task.status] != null)) {\n _this.scope.usTasks[task.user_story][task.status].push(task);\n }\n }\n return tasks;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadTaskboard = function() {\n return this.q.all([\n this.refreshTagsColors(), this.loadSprintStats(), this.loadSprint().then((function(_this) {\n return function() {\n return _this.loadTasks();\n };\n })(this))\n ]);\n };\n\n TaskboardController.prototype.loadInitialData = function() {\n var params, promise;\n params = {\n pslug: this.params.pslug,\n sslug: this.params.sslug\n };\n promise = this.repo.resolve(params).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n _this.scope.sprintId = data.milestone;\n _this.initializeSubscription();\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadTaskboard();\n };\n })(this));\n };\n\n TaskboardController.prototype.refreshTasksOrder = function(tasks) {\n var data, items;\n items = this.resortTasks(tasks);\n data = this.prepareBulkUpdateData(items);\n return this.rs.tasks.bulkUpdateTaskTaskboardOrder(this.scope.project.id, data);\n };\n\n TaskboardController.prototype.resortTasks = function(tasks) {\n var index, item, items, _i, _len;\n items = [];\n for (index = _i = 0, _len = tasks.length; _i < _len; index = ++_i) {\n item = tasks[index];\n item[\"taskboard_order\"] = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n TaskboardController.prototype.prepareBulkUpdateData = function(uses) {\n return _.map(uses, function(x) {\n return {\n \"task_id\": x.id,\n \"order\": x[\"taskboard_order\"]\n };\n });\n };\n\n TaskboardController.prototype.taskMove = function(ctx, task, usId, statusId, order) {\n var promise, r, tasks;\n r = this.scope.usTasks[task.user_story][task.status].indexOf(task);\n this.scope.usTasks[task.user_story][task.status].splice(r, 1);\n tasks = this.scope.usTasks[usId][statusId];\n tasks.splice(order, 0, task);\n task.user_story = usId;\n task.status = statusId;\n task.taskboard_order = order;\n promise = this.repo.save(task);\n this.rootscope.$broadcast(\"sprint:task:moved\", task);\n promise.then((function(_this) {\n return function() {\n _this.refreshTasksOrder(tasks);\n return _this.loadSprintStats();\n };\n })(this));\n return promise.then(null, (function(_this) {\n return function() {\n return console.log(\"FAIL TASK SAVE\");\n };\n })(this));\n };\n\n TaskboardController.prototype.addNewTask = function(type, us) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"taskform:new\", this.scope.sprintId, us != null ? us.id : void 0);\n case \"bulk\":\n return this.rootscope.$broadcast(\"taskform:bulk\", this.scope.sprintId, us != null ? us.id : void 0);\n }\n };\n\n TaskboardController.prototype.editTaskAssignedTo = function(task) {\n return this.rootscope.$broadcast(\"assigned-to:add\", task);\n };\n\n return TaskboardController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TaskboardController\", TaskboardController);\n\n TaskboardDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var $ctrl, tableBodyDom;\n $ctrl = $el.controller();\n $el.on(\"click\", \".toggle-analytics-visibility\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.toggleClass('active');\n return $rootscope.$broadcast(\"taskboard:graph:toggle-visibility\");\n });\n tableBodyDom = $el.find(\".taskboard-table-body\");\n tableBodyDom.on(\"scroll\", function(event) {\n var tableHeaderDom, target;\n target = angular.element(event.currentTarget);\n tableHeaderDom = $el.find(\".taskboard-table-header .taskboard-table-inner\");\n return tableHeaderDom.css(\"left\", -1 * target.scrollLeft());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboard\", [\"$rootScope\", TaskboardDirective]);\n\n TaskboardTaskDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $el.disableSelection();\n $scope.$watch(\"task\", function(task) {\n if (task.is_blocked && !$el.hasClass(\"blocked\")) {\n return $el.addClass(\"blocked\");\n } else if (!task.is_blocked && $el.hasClass(\"blocked\")) {\n return $el.removeClass(\"blocked\");\n }\n });\n return $el.find(\".icon-edit\").on(\"click\", function(event) {\n if ($el.find('.icon-edit').hasClass('noclick')) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"taskform:edit\", $scope.task);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardTask\", [\"$rootScope\", TaskboardTaskDirective]);\n\n TaskboardTableHeightFixerDirective = function() {\n var link, mainPadding, renderSize;\n mainPadding = 32;\n renderSize = function($el) {\n var columnHeight, elementOffset, windowHeight;\n elementOffset = $el.offset().top;\n windowHeight = angular.element(window).height();\n columnHeight = windowHeight - elementOffset - mainPadding;\n return $el.css(\"height\", \"\" + columnHeight + \"px\");\n };\n link = function($scope, $el, $attrs) {\n timeout(500, function() {\n return renderSize($el);\n });\n return $scope.$on(\"resize\", function() {\n return renderSize($el);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardTableHeightFixer\", TaskboardTableHeightFixerDirective);\n\n TaskboardSquishColumnDirective = function(rs) {\n var avatarWidth, link;\n avatarWidth = 40;\n link = function($scope, $el, $attrs) {\n var getCeilWidth, recalculateStatusColumnWidth, recalculateTaskboardWidth, refreshTaskboardTableWidth, setStatusColumnWidth;\n $scope.$on(\"sprint:task:moved\", (function(_this) {\n return function() {\n return recalculateTaskboardWidth();\n };\n })(this));\n bindOnce($scope, \"usTasks\", function(project) {\n $scope.statusesFolded = rs.tasks.getStatusColumnModes($scope.project.id);\n $scope.usFolded = rs.tasks.getUsRowModes($scope.project.id, $scope.sprintId);\n return recalculateTaskboardWidth();\n });\n $scope.foldStatus = function(status) {\n $scope.statusesFolded[status.id] = !!!$scope.statusesFolded[status.id];\n rs.tasks.storeStatusColumnModes($scope.projectId, $scope.statusesFolded);\n return recalculateTaskboardWidth();\n };\n $scope.foldUs = function(us) {\n if (!us) {\n $scope.usFolded[null] = !!!$scope.usFolded[null];\n } else {\n $scope.usFolded[us.id] = !!!$scope.usFolded[us.id];\n }\n rs.tasks.storeUsRowModes($scope.projectId, $scope.sprintId, $scope.usFolded);\n return recalculateTaskboardWidth();\n };\n getCeilWidth = (function(_this) {\n return function(usId, statusId) {\n var tasks, tasksMatrixSize, width;\n tasks = $scope.usTasks[usId][statusId].length;\n if ($scope.statusesFolded[statusId]) {\n if (tasks && $scope.usFolded[usId]) {\n tasksMatrixSize = Math.round(Math.sqrt(tasks));\n width = avatarWidth * tasksMatrixSize;\n } else {\n width = avatarWidth;\n }\n return width;\n }\n return 0;\n };\n })(this);\n setStatusColumnWidth = (function(_this) {\n return function(statusId, width) {\n var column;\n column = $el.find(\".squish-status-\" + statusId);\n if (width) {\n return column.css('max-width', width);\n } else {\n return column.css(\"max-width\", 'none');\n }\n };\n })(this);\n refreshTaskboardTableWidth = (function(_this) {\n return function() {\n var columnWidths, columns, totalWidth;\n columnWidths = [];\n columns = $el.find(\".task-colum-name\");\n columnWidths = _.map(columns, function(column) {\n return $(column).outerWidth(true);\n });\n totalWidth = _.reduce(columnWidths, function(total, width) {\n return total + width;\n });\n return $el.find('.taskboard-table-inner').css(\"width\", totalWidth);\n };\n })(this);\n recalculateStatusColumnWidth = (function(_this) {\n return function(statusId) {\n var statusFoldedWidth;\n statusFoldedWidth = getCeilWidth(null, statusId);\n _.forEach($scope.userstories, function(us) {\n var width;\n width = getCeilWidth(us.id, statusId);\n if (width > statusFoldedWidth) {\n return statusFoldedWidth = width;\n }\n });\n return setStatusColumnWidth(statusId, statusFoldedWidth);\n };\n })(this);\n return recalculateTaskboardWidth = (function(_this) {\n return function() {\n _.forEach($scope.taskStatusList, function(status) {\n return recalculateStatusColumnWidth(status.id);\n });\n refreshTaskboardTableWidth();\n };\n })(this);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardSquishColumn\", [\"$tgResources\", TaskboardSquishColumnDirective]);\n\n TaskboardUserDirective = function($log) {\n var clickable, link, template;\n template = \"
    \\n \\n \\n \\n
    \\n\\n
    \\n \\n \\n \\n
    \";\n clickable = false;\n link = function($scope, $el, $attrs) {\n var username_label;\n username_label = $el.parent().find(\"a.task-assigned\");\n username_label.on(\"click\", function(event) {\n var $ctrl;\n if ($el.find('a').hasClass('noclick')) {\n return;\n }\n $ctrl = $el.controller();\n return $ctrl.editTaskAssignedTo($scope.task);\n });\n $scope.$watch('task.assigned_to', function(assigned_to) {\n var user;\n user = $scope.usersById[assigned_to];\n if (user === void 0) {\n _.assign($scope, {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\",\n clickable: clickable\n });\n } else {\n _.assign($scope, {\n name: user.full_name_display,\n imgurl: user.photo,\n clickable: clickable\n });\n }\n return username_label.text($scope.name);\n });\n return bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_task\") > -1) {\n clickable = true;\n return $el.find(\".avatar-assigned-to\").on(\"click\", (function(_this) {\n return function(event) {\n var $ctrl;\n if ($el.find('a').hasClass('noclick')) {\n return;\n }\n $ctrl = $el.controller();\n return $ctrl.editTaskAssignedTo($scope.task);\n };\n })(this));\n }\n });\n };\n return {\n link: link,\n template: template,\n scope: {\n \"usersById\": \"=users\",\n \"project\": \"=\",\n \"task\": \"=\"\n }\n };\n };\n\n module.directive(\"tgTaskboardUserAvatar\", [\"$log\", TaskboardUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/sortable.coffee\n */\n\n(function() {\n var TaskboardSortableDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaBacklog\");\n\n TaskboardSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var deleteElement, itemEl, newParentScope, oldParentScope, tdom;\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el;\n deleteElement = function(itemEl) {\n itemEl.scope().$destroy();\n itemEl.off();\n return itemEl.remove();\n };\n tdom.sortable({\n handle: \".taskboard-task-inner\",\n dropOnEmpty: true,\n connectWith: \".taskboard-tasks-box\",\n revert: 400\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemTask, newStatusId, newUsId, oldStatusId, oldUsId, parentEl;\n parentEl = ui.item.parent();\n itemEl = ui.item;\n itemTask = itemEl.scope().task;\n itemIndex = itemEl.index();\n newParentScope = parentEl.scope();\n oldUsId = oldParentScope.us ? oldParentScope.us.id : null;\n oldStatusId = oldParentScope.st.id;\n newUsId = newParentScope.us ? newParentScope.us.id : null;\n newStatusId = newParentScope.st.id;\n if (newStatusId !== oldStatusId || newUsId !== oldUsId) {\n deleteElement(itemEl);\n }\n $scope.$apply(function() {\n return $rootscope.$broadcast(\"taskboard:task:move\", itemTask, newUsId, newStatusId, itemIndex);\n });\n return ui.item.find('a').removeClass('noclick');\n });\n tdom.on(\"sortstart\", function(event, ui) {\n oldParentScope = ui.item.parent().scope();\n return ui.item.find('a').addClass('noclick');\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", TaskboardSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban/main.coffee\n */\n\n(function() {\n var KanbanArchivedStatusHeaderDirective, KanbanArchivedStatusIntroDirective, KanbanColumnHeightFixerDirective, KanbanController, KanbanDirective, KanbanSquishColumnDirective, KanbanUserDirective, KanbanUserstoryDirective, KanbanWipLimitDirective, bindMethods, bindOnce, defaultViewMode, defaultViewModes, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaKanban\");\n\n defaultViewMode = \"maximized\";\n\n defaultViewModes = {\n maximized: {\n cardClass: \"kanban-task-maximized\"\n },\n minimized: {\n cardClass: \"kanban-task-minimized\"\n }\n };\n\n KanbanController = (function(_super) {\n __extends(KanbanController, _super);\n\n KanbanController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function KanbanController(scope, rootscope, repo, confirm, rs, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Kanban\";\n this.scope.statusViewModes = {};\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Kanban - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n KanbanController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"usform:new:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.refreshTagsColors();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"create userstory on kanban\", 1);\n };\n })(this));\n this.scope.$on(\"usform:bulk:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"bulk create userstory on kanban\", 1);\n };\n })(this));\n this.scope.$on(\"usform:edit:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n return _this.refreshTagsColors();\n };\n })(this));\n this.scope.$on(\"assigned-to:added\", this.onAssignedToChanged);\n this.scope.$on(\"kanban:us:move\", this.moveUs);\n this.scope.$on(\"kanban:show-userstories-for-status\", this.loadUserStoriesForStatus);\n return this.scope.$on(\"kanban:hide-userstories-for-status\", this.hideUserStoriesForStatus);\n };\n\n KanbanController.prototype.addNewUs = function(type, statusId) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"usform:new\", this.scope.projectId, statusId, this.scope.usStatusList);\n case \"bulk\":\n return this.rootscope.$broadcast(\"usform:bulk\", this.scope.projectId, statusId);\n }\n };\n\n KanbanController.prototype.changeUsAssignedTo = function(us) {\n return this.rootscope.$broadcast(\"assigned-to:add\", us);\n };\n\n KanbanController.prototype.onAssignedToChanged = function(ctx, userid, us) {\n var promise;\n us.assigned_to = userid;\n promise = this.repo.save(us);\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n\n KanbanController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n KanbanController.prototype.loadUserstories = function() {\n var params;\n params = {\n status__is_archived: false\n };\n return this.rs.userstories.listAll(this.scope.projectId, params).then((function(_this) {\n return function(userstories) {\n var status, usByStatus, _i, _len, _ref;\n _this.scope.userstories = userstories;\n usByStatus = _.groupBy(userstories, \"status\");\n _ref = _this.scope.usStatusList;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n status = _ref[_i];\n if (usByStatus[status.id] == null) {\n usByStatus[status.id] = [];\n }\n if (status.is_archived && (_this.scope.usByStatus != null)) {\n usByStatus[status.id] = _this.scope.usByStatus[status.id];\n }\n usByStatus[status.id] = _.sortBy(usByStatus[status.id], \"kanban_order\");\n }\n _this.scope.usByStatus = usByStatus;\n scopeDefer(_this.scope, function() {\n return _this.scope.$broadcast(\"userstories:loaded\", userstories);\n });\n return userstories;\n };\n })(this));\n };\n\n KanbanController.prototype.loadUserStoriesForStatus = function(ctx, statusId) {\n var params;\n params = {\n status: statusId\n };\n return this.rs.userstories.listAll(this.scope.projectId, params).then((function(_this) {\n return function(userstories) {\n _this.scope.usByStatus[statusId] = _.sortBy(userstories, \"kanban_order\");\n _this.scope.$broadcast(\"kanban:shown-userstories-for-status\", statusId, userstories);\n return userstories;\n };\n })(this));\n };\n\n KanbanController.prototype.hideUserStoriesForStatus = function(ctx, statusId) {\n this.scope.usByStatus[statusId] = [];\n return this.scope.$broadcast(\"kanban:hidden-userstories-for-status\", statusId);\n };\n\n KanbanController.prototype.loadKanban = function() {\n return this.q.all([this.refreshTagsColors(), this.loadUserstories()]);\n };\n\n KanbanController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.projectId = project.id;\n _this.scope.points = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(x) {\n return x.id;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.generateStatusViewModes();\n _this.scope.$emit(\"project:loaded\", project);\n return project;\n };\n })(this));\n };\n\n KanbanController.prototype.initializeSubscription = function() {\n var routingKey1;\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n return this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n return _this.loadUserstories();\n };\n })(this));\n };\n\n KanbanController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n _this.initializeSubscription();\n return _this.loadKanban().then(function() {\n return _this.scope.$broadcast(\"redraw:wip\");\n });\n };\n })(this));\n };\n\n KanbanController.prototype.generateStatusViewModes = function() {\n var mode, status, storedStatusViewModes, _i, _len, _ref;\n storedStatusViewModes = this.rs.kanban.getStatusViewModes(this.scope.projectId);\n this.scope.statusViewModes = {};\n _ref = this.scope.usStatusList;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n status = _ref[_i];\n mode = storedStatusViewModes[status.id];\n this.scope.statusViewModes[status.id] = _.has(defaultViewModes, mode) ? mode : defaultViewMode;\n }\n return this.storeStatusViewModes();\n };\n\n KanbanController.prototype.storeStatusViewModes = function() {\n return this.rs.kanban.storeStatusViewModes(this.scope.projectId, this.scope.statusViewModes);\n };\n\n KanbanController.prototype.updateStatusViewMode = function(statusId, newViewMode) {\n this.scope.statusViewModes[statusId] = newViewMode;\n return this.storeStatusViewModes();\n };\n\n KanbanController.prototype.getCardClass = function(statusId) {\n var mode;\n mode = this.scope.statusViewModes[statusId] || defaultViewMode;\n return defaultViewModes[mode].cardClass || defaultViewModes[defaultViewMode].cardClass;\n };\n\n KanbanController.prototype.prepareBulkUpdateData = function(uses, field) {\n if (field == null) {\n field = \"kanban_order\";\n }\n return _.map(uses, function(x) {\n return {\n \"us_id\": x.id,\n \"order\": x[field]\n };\n });\n };\n\n KanbanController.prototype.resortUserStories = function(uses) {\n var index, item, items, _i, _len;\n items = [];\n for (index = _i = 0, _len = uses.length; _i < _len; index = ++_i) {\n item = uses[index];\n item.kanban_order = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n KanbanController.prototype.moveUs = function(ctx, us, oldStatusId, newStatusId, index) {\n var itemsToSave, promise, r;\n if (oldStatusId !== newStatusId) {\n r = this.scope.usByStatus[oldStatusId].indexOf(us);\n this.scope.usByStatus[oldStatusId].splice(r, 1);\n this.scope.usByStatus[newStatusId].splice(index, 0, us);\n us.status = newStatusId;\n } else {\n r = this.scope.usByStatus[newStatusId].indexOf(us);\n this.scope.usByStatus[newStatusId].splice(r, 1);\n this.scope.usByStatus[newStatusId].splice(index, 0, us);\n }\n itemsToSave = this.resortUserStories(this.scope.usByStatus[newStatusId]);\n this.scope.usByStatus[newStatusId] = _.sortBy(this.scope.usByStatus[newStatusId], \"kanban_order\");\n promise = this.repo.save(us);\n promise = promise.then((function(_this) {\n return function() {\n var data;\n itemsToSave = _.reject(itemsToSave, {\n \"id\": us.id\n });\n data = _this.prepareBulkUpdateData(itemsToSave);\n return _this.rs.userstories.bulkUpdateKanbanOrder(us.project, data).then(function() {\n return itemsToSave;\n });\n };\n })(this));\n return promise;\n };\n\n return KanbanController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"KanbanController\", KanbanController);\n\n KanbanDirective = function($repo, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var tableBodyDom;\n tableBodyDom = $el.find(\".kanban-table-body\");\n tableBodyDom.on(\"scroll\", function(event) {\n var tableHeaderDom, target;\n target = angular.element(event.currentTarget);\n tableHeaderDom = $el.find(\".kanban-table-header .kanban-table-inner\");\n return tableHeaderDom.css(\"left\", -1 * target.scrollLeft());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanban\", [\"$tgRepo\", \"$rootScope\", KanbanDirective]);\n\n KanbanColumnHeightFixerDirective = function() {\n var link, mainPadding, renderSize, scrollPadding;\n mainPadding = 32;\n scrollPadding = 0;\n renderSize = function($el) {\n var columnHeight, elementOffset, windowHeight;\n elementOffset = $el.parent().parent().offset().top;\n windowHeight = angular.element(window).height();\n columnHeight = windowHeight - elementOffset - mainPadding - scrollPadding;\n return $el.css(\"height\", \"\" + columnHeight + \"px\");\n };\n link = function($scope, $el, $attrs) {\n timeout(500, function() {\n return renderSize($el);\n });\n $scope.$on(\"resize\", function() {\n return renderSize($el);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanColumnHeightFixer\", KanbanColumnHeightFixerDirective);\n\n KanbanArchivedStatusHeaderDirective = function($rootscope) {\n var hideArchivedText, link, showArchivedText;\n showArchivedText = \"Show archived\";\n hideArchivedText = \"Hide archived\";\n link = function($scope, $el, $attrs) {\n var hidden, status;\n status = $scope.$eval($attrs.tgKanbanArchivedStatusHeader);\n hidden = true;\n $scope[\"class\"] = \"icon icon-open-eye\";\n $scope.title = showArchivedText;\n $el.on(\"click\", function(event) {\n hidden = !hidden;\n return $scope.$apply(function() {\n if (hidden) {\n $scope[\"class\"] = \"icon icon-open-eye\";\n $scope.title = showArchivedText;\n return $rootscope.$broadcast(\"kanban:hide-userstories-for-status\", status.id);\n } else {\n $scope[\"class\"] = \"icon icon-closed-eye\";\n $scope.title = hideArchivedText;\n return $rootscope.$broadcast(\"kanban:show-userstories-for-status\", status.id);\n }\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanArchivedStatusHeader\", [\"$rootScope\", KanbanArchivedStatusHeaderDirective]);\n\n KanbanArchivedStatusIntroDirective = function() {\n var hiddenUserStoriexText, link, userStories;\n hiddenUserStoriexText = \"The user stories in this status are hidden by default\";\n userStories = [];\n link = function($scope, $el, $attrs) {\n var status, updateIntroText;\n status = $scope.$eval($attrs.tgKanbanArchivedStatusIntro);\n $el.text(hiddenUserStoriexText);\n updateIntroText = function() {\n if (userStories.length > 0) {\n return $el.text(\"\");\n } else {\n return $el.text(hiddenUserStoriexText);\n }\n };\n $scope.$on(\"kanban:us:move\", function(ctx, itemUs, oldStatusId, newStatusId, itemIndex) {\n var r;\n if (status.id === newStatusId) {\n if (status.id === oldStatusId) {\n r = userStories.indexOf(itemUs);\n userStories.splice(r, 1);\n userStories.splice(itemIndex, 0, itemUs);\n } else {\n itemUs.isArchived = true;\n userStories.splice(itemIndex, 0, itemUs);\n }\n } else if (status.id === oldStatusId) {\n itemUs.isArchived = false;\n r = userStories.indexOf(itemUs);\n userStories.splice(r, 1);\n }\n return updateIntroText();\n });\n $scope.$on(\"kanban:shown-userstories-for-status\", function(ctx, statusId, userStoriesLoaded) {\n if (statusId === status.id) {\n userStories = _.filter(userStoriesLoaded, function(us) {\n return us.status === status.id;\n });\n return updateIntroText();\n }\n });\n $scope.$on(\"kanban:hidden-userstories-for-status\", function(ctx, statusId) {\n if (statusId === status.id) {\n userStories = [];\n return updateIntroText();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanArchivedStatusIntro\", KanbanArchivedStatusIntroDirective);\n\n KanbanUserstoryDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $el.disableSelection();\n $scope.$watch(\"us\", function(us) {\n if (us.is_blocked && !$el.hasClass(\"blocked\")) {\n return $el.addClass(\"blocked\");\n } else if (!us.is_blocked && $el.hasClass(\"blocked\")) {\n return $el.removeClass(\"blocked\");\n }\n });\n $el.find(\".icon-edit\").on(\"click\", function(event) {\n if ($el.find(\".icon-edit\").hasClass(\"noclick\")) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"usform:edit\", $model.$modelValue);\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"/partials/views/components/kanban-task.html\",\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgKanbanUserstory\", [\"$rootScope\", KanbanUserstoryDirective]);\n\n KanbanSquishColumnDirective = function(rs) {\n var link;\n link = function($scope, $el, $attrs) {\n var updateTableWidth;\n $scope.$on(\"project:loaded\", function(event, project) {\n $scope.folds = rs.kanban.getStatusColumnModes(project.id);\n return updateTableWidth();\n });\n $scope.foldStatus = function(status) {\n $scope.folds[status.id] = !!!$scope.folds[status.id];\n rs.kanban.storeStatusColumnModes($scope.projectId, $scope.folds);\n updateTableWidth();\n };\n return updateTableWidth = function() {\n var columnWidths, totalWidth;\n columnWidths = _.map($scope.usStatusList, function(status) {\n if ($scope.folds[status.id]) {\n return 40;\n } else {\n return 310;\n }\n });\n totalWidth = _.reduce(columnWidths, function(total, width) {\n return total + width;\n });\n return $el.find('.kanban-table-inner').css(\"width\", totalWidth);\n };\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanSquishColumn\", [\"$tgResources\", KanbanSquishColumnDirective]);\n\n KanbanWipLimitDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var redrawWipLimit;\n $el.disableSelection();\n redrawWipLimit = function() {\n $el.find(\".kanban-wip-limit\").remove();\n return timeout(200, function() {\n var element;\n element = $el.find(\".kanban-task\")[$scope.$eval($attrs.tgKanbanWipLimit)];\n if (element) {\n return angular.element(element).before(\"
    \");\n }\n });\n };\n $scope.$on(\"redraw:wip\", redrawWipLimit);\n $scope.$on(\"kanban:us:move\", redrawWipLimit);\n $scope.$on(\"usform:new:success\", redrawWipLimit);\n $scope.$on(\"usform:bulk:success\", redrawWipLimit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanWipLimit\", KanbanWipLimitDirective);\n\n KanbanUserDirective = function($log) {\n var clickable, link, template;\n template = _.template(\"
    \\n class=\\\"not-clickable\\\"<% } %>>\\n \\\" alt=\\\"<%- name %>\\\" class=\\\"avatar\\\">\\n \\n
    \");\n clickable = false;\n link = function($scope, $el, $attrs, $model) {\n var render, wtid;\n if (!$attrs.tgKanbanUserAvatar) {\n return $log.error(\"KanbanUserDirective: no attr is defined\");\n }\n wtid = $scope.$watch($attrs.tgKanbanUserAvatar, function(v) {\n var user;\n if ($scope.usersById == null) {\n $log.error(\"KanbanUserDirective requires userById set in scope.\");\n return wtid();\n } else {\n user = $scope.usersById[v];\n return render(user);\n }\n });\n render = function(user) {\n var ctx, html, username_label;\n if (user === void 0) {\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\",\n clickable: clickable\n };\n } else {\n ctx = {\n name: user.full_name_display,\n imgurl: user.photo,\n clickable: clickable\n };\n }\n html = template(ctx);\n $el.html(html);\n username_label = $el.parent().find(\"a.task-assigned\");\n username_label.html(ctx.name);\n return username_label.on(\"click\", function(event) {\n var $ctrl, us;\n if ($el.find(\"a\").hasClass(\"noclick\")) {\n return;\n }\n us = $model.$modelValue;\n $ctrl = $el.controller();\n return $ctrl.changeUsAssignedTo(us);\n });\n };\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n clickable = true;\n return $el.on(\"click\", (function(_this) {\n return function(event) {\n var $ctrl, us;\n if ($el.find(\"a\").hasClass(\"noclick\")) {\n return;\n }\n us = $model.$modelValue;\n $ctrl = $el.controller();\n return $ctrl.changeUsAssignedTo(us);\n };\n })(this));\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgKanbanUserAvatar\", [\"$log\", KanbanUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban/sortable.coffee\n */\n\n(function() {\n var KanbanSortableDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaKanban\");\n\n KanbanSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var deleteElement, itemEl, newParentScope, oldParentScope, tdom;\n if (!(project.my_permissions.indexOf(\"modify_us\") > -1)) {\n return;\n }\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el;\n deleteElement = function(itemEl) {\n itemEl.scope().$destroy();\n itemEl.off();\n return itemEl.remove();\n };\n tdom.sortable({\n handle: \".kanban-task-inner\",\n dropOnEmpty: true,\n connectWith: \".kanban-uses-box\",\n revert: 400\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemUs, newStatusId, oldStatusId, parentEl;\n parentEl = ui.item.parent();\n itemEl = ui.item;\n itemUs = itemEl.scope().us;\n itemIndex = itemEl.index();\n newParentScope = parentEl.scope();\n newStatusId = newParentScope.s.id;\n oldStatusId = oldParentScope.s.id;\n if (newStatusId !== oldStatusId) {\n deleteElement(itemEl);\n }\n $scope.$apply(function() {\n return $rootscope.$broadcast(\"kanban:us:move\", itemUs, itemUs.status, newStatusId, itemIndex);\n });\n return ui.item.find('a').removeClass('noclick');\n });\n return tdom.on(\"sortstart\", function(event, ui) {\n oldParentScope = ui.item.parent().scope();\n return ui.item.find('a').addClass('noclick');\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", KanbanSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/detail.coffee\n */\n\n(function() {\n var IssueDetailController, IssuePriorityButtonDirective, IssueSeverityButtonDirective, IssueStatusButtonDirective, IssueStatusDisplayDirective, IssueTypeButtonDirective, PromoteIssueToUsButtonDirective, bindOnce, groupBy, joinStr, mixOf, module, taiga, toString,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaIssues\");\n\n IssueDetailController = (function(_super) {\n __extends(IssueDetailController, _super);\n\n IssueDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgAnalytics\", \"$tgNavUrls\", \"tgLoader\"];\n\n function IssueDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, analytics, navUrls, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.analytics = analytics;\n this.navUrls = navUrls;\n this.scope.issueRef = this.params.issueref;\n this.scope.sectionName = \"Issue Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.issue.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n IssueDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.rootscope.$broadcast(\"history:reload\");\n return _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on issue\", 1);\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"promote-issue-to-us:success\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"issue\", \"promoteToUserstory\", \"promote issue to userstory\", 1);\n _this.rootscope.$broadcast(\"history:reload\");\n return _this.loadIssue();\n };\n })(this));\n };\n\n IssueDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n if (this.scope.project.is_issues_activated) {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-issues\", ctx);\n } else {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n }\n };\n\n IssueDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.issue_statuses;\n _this.scope.statusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.typeById = groupBy(project.issue_types, function(x) {\n return x.id;\n });\n _this.scope.typeList = _.sortBy(project.issue_types, \"order\");\n _this.scope.severityList = project.severities;\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.priorityList = project.priorities;\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n IssueDetailController.prototype.loadIssue = function() {\n return this.rs.issues.getByRef(this.scope.projectId, this.params.issueref).then((function(_this) {\n return function(issue) {\n var ctx;\n _this.scope.issue = issue;\n _this.scope.issueId = issue.id;\n _this.scope.commentModel = issue;\n if (_this.scope.issue.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.issue.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-issues-detail\", ctx);\n }\n if (_this.scope.issue.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.issue.neighbors.next.ref\n };\n return _this.scope.nextUrl = _this.navUrls.resolve(\"project-issues-detail\", ctx);\n }\n };\n })(this));\n };\n\n IssueDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadIssue();\n };\n })(this));\n };\n\n return IssueDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"IssueDetailController\", IssueDetailController);\n\n IssueStatusDisplayDirective = function() {\n var link, template;\n template = _.template(\"\\n <% if (status.is_closed) { %>\\n Closed\\n <% } else { %>\\n Open\\n <% } %>\\n\\n\\\">\\n <%- status.name %>\\n\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function(issue) {\n var html;\n html = template({\n status: $scope.statusById[issue.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue != null) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueStatusDisplay\", IssueStatusDisplayDirective);\n\n IssueStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- status.name %>\\n <% if(editable){ %><% }%>\\n status\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, status;\n status = $scope.statusById[issue.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(value, issue) {\n var onError, onSuccess;\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save(value).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var issue, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.status = target.data(\"status-id\");\n $model.$setViewValue(issue);\n return save($model.$modelValue, issue);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", IssueStatusButtonDirective]);\n\n IssueTypeButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- type.name %>\\n <% if(editable){ %><% }%>\\n type\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, type;\n type = $scope.typeById[issue.type];\n html = template({\n type: type,\n typees: $scope.typeList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(type) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.type = type;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".type-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-type\").popover().open();\n });\n $el.on(\"click\", \".type\", function(event) {\n var target, type;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n type = target.data(\"type-id\");\n return save(type);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueTypeButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", IssueTypeButtonDirective]);\n\n IssueSeverityButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- severity.name %>\\n <% if(editable){ %><% }%>\\n severity\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, severity;\n severity = $scope.severityById[issue.severity];\n html = template({\n severity: severity,\n severityes: $scope.severityList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(severity) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.severity = severity;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".severity-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-severity\").popover().open();\n });\n $el.on(\"click\", \".severity\", function(event) {\n var severity, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n severity = target.data(\"severity-id\");\n return save(severity);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueSeverityButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", IssueSeverityButtonDirective]);\n\n IssuePriorityButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- priority.name %>\\n <% if(editable){ %><% }%>\\n priority\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, priority;\n priority = $scope.priorityById[issue.priority];\n html = template({\n priority: priority,\n priorityes: $scope.priorityList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(priority) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.priority = priority;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".priority-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-priority\").popover().open();\n });\n $el.on(\"click\", \".priority\", function(event) {\n var priority, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n priority = target.data(\"priority-id\");\n return save(priority);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssuePriorityButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", IssuePriorityButtonDirective]);\n\n PromoteIssueToUsButtonDirective = function($rootScope, $repo, $confirm, $qqueue) {\n var link, template;\n template = _.template(\"\\n Promote to User Story\\n\");\n link = function($scope, $el, $attrs, $model) {\n var save;\n save = $qqueue.bindAdd((function(_this) {\n return function(issue, finish) {\n var data, onError, onSuccess;\n data = {\n generated_from_issue: issue.id,\n project: issue.project,\n subject: issue.subject,\n description: issue.description,\n tags: issue.tags,\n is_blocked: issue.is_blocked,\n blocked_note: issue.blocked_note\n };\n onSuccess = function() {\n finish();\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"promote-issue-to-us:success\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\");\n };\n return $repo.create(\"userstories\", data).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \"a\", function(event) {\n var issue, message, subtitle, title;\n event.preventDefault();\n issue = $model.$modelValue;\n title = \"Promote this issue to a new user story\";\n message = \"Are you sure you want to create a new US from this Issue?\";\n subtitle = issue.subject;\n return $confirm.ask(title, subtitle, message).then((function(_this) {\n return function(finish) {\n return save(issue, finish);\n };\n })(this));\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n restrict: \"AE\",\n require: \"ngModel\",\n template: template,\n link: link\n };\n };\n\n module.directive(\"tgPromoteIssueToUsButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgQqueue\", PromoteIssueToUsButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/lightboxes.coffee\n */\n\n(function() {\n var CreateBulkIssuesDirective, CreateIssueDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaIssues\");\n\n CreateIssueDirective = function($repo, $confirm, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley();\n $scope.issue = {};\n $scope.$on(\"issueform:new\", function(ctx, project) {\n $el.find(\".tag-input\").val(\"\");\n lightboxService.open($el);\n return $scope.issue = {\n project: project.id,\n subject: \"\",\n status: project.default_issue_status,\n type: project.default_issue_type,\n priority: project.default_priority,\n severity: project.default_severity,\n tags: []\n };\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"issues\", $scope.issue);\n promise.then(function(data) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"issueform:new:success\", data);\n lightboxService.close($el);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateIssue\", [\"$tgRepo\", \"$tgConfirm\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateIssueDirective]);\n\n CreateBulkIssuesDirective = function($repo, $rs, $confirm, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.$on(\"issueform:bulk\", function(ctx, projectId, status) {\n lightboxService.open($el);\n return $scope[\"new\"] = {\n projectId: projectId,\n bulk: \"\"\n };\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, projectId, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n data = $scope[\"new\"].bulk;\n projectId = $scope[\"new\"].projectId;\n promise = $rs.issues.bulkCreate(projectId, data);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"issueform:new:success\", result);\n lightboxService.close($el);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateBulkIssues\", [\"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateBulkIssuesDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/list.coffee\n */\n\n(function() {\n var IssueAssignedToInlineEditionDirective, IssueStatusInlineEditionDirective, IssuesController, IssuesDirective, IssuesFiltersDirective, bindOnce, debounceLeading, groupBy, joinStr, mixOf, module, paginatorTemplate, startswith, taiga, toString, trim,\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounceLeading = this.taiga.debounceLeading;\n\n startswith = this.taiga.startswith;\n\n module = angular.module(\"taigaIssues\");\n\n IssuesController = (function(_super) {\n __extends(IssuesController, _super);\n\n IssuesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$tgUrls\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function IssuesController(scope, rootscope, repo, confirm, rs, urls, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var filters, promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.urls = urls;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n this.loadIssues = __bind(this.loadIssues, this);\n this.scope.sectionName = \"Issues\";\n this.scope.filters = {};\n if (_.isEmpty(this.location.search())) {\n filters = this.rs.issues.getFilters(this.params.pslug);\n filters.page = 1;\n this.location.search(filters);\n this.location.replace();\n return;\n }\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Issues - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n this.scope.$on(\"issueform:new:success\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"issue\", \"create\", \"create issue on issues list\", 1);\n _this.loadIssues();\n return _this.loadFilters();\n };\n })(this));\n }\n\n IssuesController.prototype.initializeSubscription = function() {\n var routingKey;\n routingKey = \"changes.project.\" + this.scope.projectId + \".issues\";\n return this.events.subscribe(this.scope, routingKey, (function(_this) {\n return function(message) {\n return _this.loadIssues();\n };\n })(this));\n };\n\n IssuesController.prototype.storeFilters = function() {\n return this.rs.issues.storeFilters(this.params.pslug, this.location.search());\n };\n\n IssuesController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issueStatusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.issueStatusList = _.sortBy(project.issue_statuses, \"order\");\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.severityList = _.sortBy(project.severities, \"order\");\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.priorityList = _.sortBy(project.priorities, \"order\");\n _this.scope.issueTypes = _.sortBy(project.issue_types, \"order\");\n _this.scope.issueTypeById = groupBy(project.issue_types, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n IssuesController.prototype.getUrlFilters = function() {\n var filters;\n filters = _.pick(this.location.search(), \"page\", \"tags\", \"statuses\", \"types\", \"q\", \"severities\", \"priorities\", \"assignedTo\", \"createdBy\", \"orderBy\");\n if (!filters.page) {\n filters.page = 1;\n }\n return filters;\n };\n\n IssuesController.prototype.getUrlFilter = function(name) {\n var filters;\n filters = _.pick(this.location.search(), name);\n return filters[name];\n };\n\n IssuesController.prototype.loadMyFilters = function() {\n return this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n return _.map(filters, function(value, key) {\n return {\n id: key,\n name: key,\n type: \"myFilters\",\n selected: false\n };\n });\n };\n })(this));\n };\n\n IssuesController.prototype.removeNotExistingFiltersFromUrl = function() {\n var currentSearch, existingValues, filterName, filterValue, splittedValues, urlfilters;\n currentSearch = this.location.search();\n urlfilters = this.getUrlFilters();\n for (filterName in urlfilters) {\n filterValue = urlfilters[filterName];\n if (filterName === \"page\" || filterName === \"orderBy\" || filterName === \"q\") {\n continue;\n }\n if (filterName === \"tags\") {\n splittedValues = _.map((\"\" + filterValue).split(\",\"));\n } else {\n splittedValues = _.map((\"\" + filterValue).split(\",\"), function(x) {\n if (x === \"null\") {\n return null;\n } else {\n return parseInt(x);\n }\n });\n }\n existingValues = _.intersection(splittedValues, _.map(this.scope.filters[filterName], \"id\"));\n if (splittedValues.length !== existingValues.length) {\n this.location.search(filterName, existingValues.join());\n }\n }\n if (currentSearch !== this.location.search()) {\n return this.location.replace();\n }\n };\n\n IssuesController.prototype.markSelectedFilters = function(filters, urlfilters) {\n var isSelected, key, name, obj, searchdata, val, value, _i, _len, _ref, _ref1, _results;\n searchdata = {};\n _ref = _.omit(urlfilters, \"page\", \"orderBy\");\n for (name in _ref) {\n value = _ref[name];\n if (searchdata[name] == null) {\n searchdata[name] = {};\n }\n _ref1 = (\"\" + value).split(\",\");\n for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n val = _ref1[_i];\n searchdata[name][val] = true;\n }\n }\n isSelected = function(type, id) {\n if ((searchdata[type] != null) && searchdata[type][id]) {\n return true;\n }\n return false;\n };\n _results = [];\n for (key in filters) {\n value = filters[key];\n _results.push((function() {\n var _j, _len1, _results1;\n _results1 = [];\n for (_j = 0, _len1 = value.length; _j < _len1; _j++) {\n obj = value[_j];\n _results1.push(obj.selected = isSelected(obj.type, obj.id) ? true : void 0);\n }\n return _results1;\n })());\n }\n return _results;\n };\n\n IssuesController.prototype.loadFilters = function() {\n var promise, urlfilters;\n urlfilters = this.getUrlFilters();\n if (urlfilters.q) {\n this.scope.filtersQ = urlfilters.q;\n }\n promise = this.loadMyFilters().then((function(_this) {\n return function(myFilters) {\n _this.scope.filters.myFilters = myFilters;\n return myFilters;\n };\n })(this));\n promise = promise.then((function(_this) {\n return function() {\n return _this.rs.issues.filtersData(_this.scope.projectId);\n };\n })(this));\n return promise.then((function(_this) {\n return function(data) {\n var choicesFiltersFormat, tagsFilterFormat, usersFiltersFormat;\n usersFiltersFormat = function(users, type, unknownOption) {\n var reformatedUsers, unknownItem;\n reformatedUsers = _.map(users, function(t) {\n return {\n id: t[0],\n count: t[1],\n type: type,\n name: t[0] ? _this.scope.usersById[t[0]].full_name_display : unknownOption\n };\n });\n unknownItem = _.remove(reformatedUsers, function(u) {\n return !u.id;\n });\n reformatedUsers = _.sortBy(reformatedUsers, function(u) {\n return u.name.toUpperCase();\n });\n if (unknownItem.length > 0) {\n reformatedUsers.unshift(unknownItem[0]);\n }\n return reformatedUsers;\n };\n choicesFiltersFormat = function(choices, type, byIdObject) {\n return _.map(choices, function(t) {\n return {\n id: t[0],\n name: byIdObject[t[0]].name,\n color: byIdObject[t[0]].color,\n count: t[1],\n type: type\n };\n });\n };\n tagsFilterFormat = function(tags) {\n return _.map(tags, function(t) {\n return {\n id: t[0],\n name: t[0],\n color: _this.scope.project.tags_colors[t[0]],\n count: t[1],\n type: \"tags\"\n };\n });\n };\n _this.scope.filters.statuses = choicesFiltersFormat(data.statuses, \"statuses\", _this.scope.issueStatusById);\n _this.scope.filters.severities = choicesFiltersFormat(data.severities, \"severities\", _this.scope.severityById);\n _this.scope.filters.priorities = choicesFiltersFormat(data.priorities, \"priorities\", _this.scope.priorityById);\n _this.scope.filters.assignedTo = usersFiltersFormat(data.assigned_to, \"assignedTo\", \"Unassigned\");\n _this.scope.filters.createdBy = usersFiltersFormat(data.created_by, \"createdBy\", \"Unknown\");\n _this.scope.filters.types = choicesFiltersFormat(data.types, \"types\", _this.scope.issueTypeById);\n _this.scope.filters.tags = tagsFilterFormat(data.tags);\n _this.removeNotExistingFiltersFromUrl();\n _this.markSelectedFilters(_this.scope.filters, urlfilters);\n return _this.rootscope.$broadcast(\"filters:loaded\", _this.scope.filters);\n };\n })(this));\n };\n\n IssuesController.prototype.loadIssuesRequests = 0;\n\n IssuesController.prototype.loadIssues = function() {\n var name, promise, values, _ref;\n this.scope.urlFilters = this.getUrlFilters();\n this.scope.httpParams = {};\n _ref = this.scope.urlFilters;\n for (name in _ref) {\n values = _ref[name];\n if (name === \"severities\") {\n name = \"severity\";\n } else if (name === \"orderBy\") {\n name = \"order_by\";\n } else if (name === \"priorities\") {\n name = \"priority\";\n } else if (name === \"assignedTo\") {\n name = \"assigned_to\";\n } else if (name === \"createdBy\") {\n name = \"owner\";\n } else if (name === \"statuses\") {\n name = \"status\";\n } else if (name === \"types\") {\n name = \"type\";\n }\n this.scope.httpParams[name] = values;\n }\n promise = this.rs.issues.list(this.scope.projectId, this.scope.httpParams);\n this.loadIssuesRequests += 1;\n promise.index = this.loadIssuesRequests;\n return promise.then((function(_this) {\n return function(data) {\n if (promise.index === _this.loadIssuesRequests) {\n _this.scope.issues = data.models;\n _this.scope.page = data.current;\n _this.scope.count = data.count;\n _this.scope.paginatedBy = data.paginatedBy;\n }\n return data;\n };\n })(this));\n };\n\n IssuesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n _this.initializeSubscription();\n return _this.q.all([_this.loadFilters(), _this.loadIssues()]);\n };\n })(this));\n };\n\n IssuesController.prototype.saveCurrentFiltersTo = function(newFilter) {\n var deferred;\n deferred = this.q.defer();\n this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n filters[newFilter] = _this.location.search();\n return _this.rs.issues.storeMyFilters(_this.scope.projectId, filters).then(function() {\n return deferred.resolve();\n });\n };\n })(this));\n return deferred.promise;\n };\n\n IssuesController.prototype.deleteMyFilter = function(filter) {\n var deferred;\n deferred = this.q.defer();\n this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n delete filters[filter];\n return _this.rs.issues.storeMyFilters(_this.scope.projectId, filters).then(function() {\n return deferred.resolve();\n });\n };\n })(this));\n return deferred.promise;\n };\n\n IssuesController.prototype.addNewIssue = function() {\n return this.rootscope.$broadcast(\"issueform:new\", this.scope.project);\n };\n\n IssuesController.prototype.addIssuesInBulk = function() {\n return this.rootscope.$broadcast(\"issueform:bulk\", this.scope.projectId);\n };\n\n return IssuesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"IssuesController\", IssuesController);\n\n paginatorTemplate = \"
      \\n <% if (showPrevious) { %>\\n
    • \\n \\n Prev\\n \\n
    • \\n <% } %>\\n\\n <% _.each(pages, function(item) { %>\\n
    • \\\">\\n <% if (item.type === \\\"page\\\") { %>\\n \\\"><%- item.num %>\\n <% } else if (item.type === \\\"page-active\\\") { %>\\n <%- item.num %>\\n <% } else { %>\\n ...\\n <% } %>\\n
    • \\n <% }); %>\\n\\n <% if (showNext) { %>\\n
    • \\n \\n Next\\n \\n
    • \\n <% } %>\\n
    \";\n\n IssuesDirective = function($log, $location) {\n var link, linkOrdering, linkPagination, template;\n template = _.template(paginatorTemplate);\n linkPagination = function($scope, $el, $attrs, $ctrl) {\n var $pagEl, afterCurrent, atBegin, atEnd, beforeCurrent, getNumPages, renderPagination;\n afterCurrent = 2;\n beforeCurrent = 4;\n atBegin = 2;\n atEnd = 2;\n $pagEl = $el.find(\".issues-paginator\");\n getNumPages = function() {\n var numPages;\n numPages = $scope.count / $scope.paginatedBy;\n if (parseInt(numPages, 10) < numPages) {\n numPages = parseInt(numPages, 10) + 1;\n } else {\n numPages = parseInt(numPages, 10);\n }\n return numPages;\n };\n renderPagination = function() {\n var cpage, i, numPages, options, pages, _i;\n numPages = getNumPages();\n if (numPages <= 1) {\n $pagEl.hide();\n return;\n }\n $pagEl.show();\n pages = [];\n options = {};\n options.pages = pages;\n options.showPrevious = $scope.page > 1;\n options.showNext = !($scope.page === numPages);\n cpage = $scope.page;\n for (i = _i = 1; 1 <= numPages ? _i <= numPages : _i >= numPages; i = 1 <= numPages ? ++_i : --_i) {\n if (i === (cpage + afterCurrent) && numPages > (cpage + afterCurrent + atEnd)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i === (cpage - beforeCurrent) && cpage > (atBegin + beforeCurrent)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i > (cpage + afterCurrent) && i <= (numPages - atEnd)) {\n\n } else if (i < (cpage - beforeCurrent) && i > atBegin) {\n\n } else if (i === cpage) {\n pages.push({\n classes: \"active\",\n num: i,\n type: \"page-active\"\n });\n } else {\n pages.push({\n classes: \"page\",\n num: i,\n type: \"page\"\n });\n }\n }\n return $pagEl.html(template(options));\n };\n $scope.$watch(\"issues\", function(value) {\n if (!value) {\n return;\n }\n return renderPagination();\n });\n $el.on(\"click\", \".issues-paginator a.next\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page + 1);\n return $ctrl.loadIssues();\n });\n });\n $el.on(\"click\", \".issues-paginator a.previous\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page - 1);\n return $ctrl.loadIssues();\n });\n });\n return $el.on(\"click\", \".issues-paginator li.page > a\", function(event) {\n var pagenum, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n pagenum = target.data(\"pagenum\");\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", pagenum);\n return $ctrl.loadIssues();\n });\n });\n };\n linkOrdering = function($scope, $el, $attrs, $ctrl) {\n var colHeadElement, currentOrder, icon;\n currentOrder = $ctrl.getUrlFilter(\"orderBy\") || \"created_date\";\n if (currentOrder) {\n icon = startswith(currentOrder, \"-\") ? \"icon-caret-up\" : \"icon-caret-down\";\n colHeadElement = $el.find(\".row.title > div[data-fieldname='\" + (trim(currentOrder, \"-\")) + \"']\");\n colHeadElement.html(\"\" + (colHeadElement.html()) + \"\");\n }\n return $el.on(\"click\", \".row.title > div\", function(event) {\n var finalOrder, newOrder, target;\n target = angular.element(event.currentTarget);\n currentOrder = $ctrl.getUrlFilter(\"orderBy\");\n newOrder = target.data(\"fieldname\");\n finalOrder = currentOrder === newOrder ? \"-\" + newOrder : newOrder;\n return $scope.$apply(function() {\n $ctrl.replaceFilter(\"orderBy\", finalOrder);\n $ctrl.storeFilters();\n return $ctrl.loadIssues().then(function() {\n $el.find(\".row.title > div > span.icon\").remove();\n icon = startswith(finalOrder, \"-\") ? \"icon-caret-up\" : \"icon-caret-down\";\n return target.html(\"\" + (target.html()) + \"\");\n });\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n linkOrdering($scope, $el, $attrs, $ctrl);\n linkPagination($scope, $el, $attrs, $ctrl);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssues\", [\"$log\", \"$tgLocation\", IssuesDirective]);\n\n IssuesFiltersDirective = function($log, $location, $rs, $confirm, $loading) {\n var link, template, templateSelected;\n template = _.template(\"<% _.each(filters, function(f) { %>\\n <% if (!f.selected) { %>\\n \\\"\\n data-id=\\\"<%- f.id %>\\\">\\n style=\\\"border-left: 3px solid <%- f.color %>;\\\"<% } %>>\\n <%- f.name %>\\n \\n <% if (f.count){ %>\\n <%- f.count %>\\n <% } %>\\n <% if (f.type == \\\"myFilters\\\"){ %>\\n \\n <% } %>\\n \\n <% } %>\\n<% }) %>\\n\\n \\n\");\n templateSelected = _.template(\"<% _.each(filters, function(f) { %>\\n\\\"\\n data-id=\\\"<%- f.id %>\\\">\\n style=\\\"border-left: 3px solid <%- f.color %>;\\\"<% } %>>\\n <%- f.name %>\\n \\n \\n\\n<% }) %>\");\n link = function($scope, $el, $attrs) {\n var $ctrl, initializeSelectedFilters, renderFilters, renderSelectedFilters, selectQFilter, selectedFilters, showCategories, showFilters, toggleFilterSelection;\n $ctrl = $el.closest(\".wrapper\").controller();\n selectedFilters = [];\n showFilters = function(title, type) {\n $el.find(\".filters-cats\").hide();\n $el.find(\".filter-list\").removeClass(\"hidden\");\n $el.find(\"h2.breadcrumb\").removeClass(\"hidden\");\n $el.find(\"h2 a.subfilter span.title\").html(title);\n return $el.find(\"h2 a.subfilter span.title\").prop(\"data-type\", type);\n };\n showCategories = function() {\n $el.find(\".filters-cats\").show();\n $el.find(\".filter-list\").addClass(\"hidden\");\n return $el.find(\"h2.breadcrumb\").addClass(\"hidden\");\n };\n initializeSelectedFilters = function(filters) {\n var name, val, values, _i, _len;\n selectedFilters = [];\n for (name in filters) {\n values = filters[name];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n val = values[_i];\n if (val.selected) {\n selectedFilters.push(val);\n }\n }\n }\n return renderSelectedFilters(selectedFilters);\n };\n renderSelectedFilters = function(selectedFilters) {\n var html;\n html = templateSelected({\n filters: selectedFilters\n });\n $el.find(\".filters-applied\").html(html);\n if (selectedFilters.length > 0) {\n return $el.find(\".save-filters\").show();\n } else {\n return $el.find(\".save-filters\").hide();\n }\n };\n renderFilters = function(filters) {\n var html;\n html = template({\n filters: filters\n });\n return $el.find(\".filter-list\").html(html);\n };\n toggleFilterSelection = function(type, id) {\n var currentFiltersType, filter, filterId, filters;\n if (type === \"myFilters\") {\n $rs.issues.getMyFilters($scope.projectId).then(function(data) {\n var filters, myFilters;\n myFilters = data;\n filters = myFilters[id];\n filters.page = 1;\n $ctrl.replaceAllFilters(filters);\n $ctrl.storeFilters();\n $ctrl.loadIssues();\n $ctrl.markSelectedFilters($scope.filters, filters);\n return initializeSelectedFilters($scope.filters);\n });\n return null;\n }\n filters = $scope.filters[type];\n filterId = type === 'tags' ? taiga.toString(id) : id;\n filter = _.find(filters, {\n id: filterId\n });\n filter.selected = !filter.selected;\n if (id === null) {\n id = \"null\";\n }\n if (filter.selected) {\n selectedFilters.push(filter);\n $scope.$apply(function() {\n $ctrl.selectFilter(type, id);\n $ctrl.selectFilter(\"page\", 1);\n $ctrl.storeFilters();\n return $ctrl.loadIssues();\n });\n } else {\n selectedFilters = _.reject(selectedFilters, filter);\n $scope.$apply(function() {\n $ctrl.unselectFilter(type, id);\n $ctrl.selectFilter(\"page\", 1);\n $ctrl.storeFilters();\n return $ctrl.loadIssues();\n });\n }\n renderSelectedFilters(selectedFilters);\n currentFiltersType = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (type === currentFiltersType) {\n return renderFilters(_.reject(filters, \"selected\"));\n }\n };\n $scope.$on(\"filters:loaded\", function(ctx, filters) {\n return initializeSelectedFilters(filters);\n });\n selectQFilter = debounceLeading(100, function(value) {\n if (value === void 0) {\n return;\n }\n if (value.length === 0) {\n $ctrl.replaceFilter(\"q\", null);\n $ctrl.storeFilters();\n } else {\n $ctrl.replaceFilter(\"q\", value);\n $ctrl.storeFilters();\n }\n return $ctrl.loadIssues();\n });\n $scope.$watch(\"filtersQ\", selectQFilter);\n $el.on(\"click\", \".filters-cats > ul > li > a\", function(event) {\n var tags, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n tags = $scope.filters[target.data(\"type\")];\n renderFilters(_.reject(tags, \"selected\"));\n return showFilters(target.attr(\"title\"), target.data(\"type\"));\n });\n $el.on(\"click\", \".filters-inner > .filters-step-cat > .breadcrumb > .back\", function(event) {\n event.preventDefault();\n return showCategories($el);\n });\n $el.on(\"click\", \".filters-applied a\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n id = target.data(\"id\") || null;\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n $el.on(\"click\", \".filter-list .single-filter\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.toggleClass(\"active\");\n id = target.data(\"id\") || null;\n type = target.data(\"type\");\n if (type === \"myFilters\") {\n target.removeClass(\"active\");\n }\n return toggleFilterSelection(type, id);\n });\n $el.on(\"click\", \".filter-list .single-filter .icon-delete\", function(event) {\n var customFilterName, message, target, title;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n customFilterName = target.parent().data('id');\n title = \"Delete custom filter\";\n message = \"the custom filter '\" + customFilterName + \"'\";\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var promise;\n promise = $ctrl.deleteMyFilter(customFilterName);\n promise.then(function() {\n promise = $ctrl.loadMyFilters();\n promise.then(function(filters) {\n finish();\n $scope.filters.myFilters = filters;\n return renderFilters($scope.filters.myFilters);\n });\n return promise.then(null, function() {\n return finish();\n });\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n });\n });\n $el.on(\"click\", \".save-filters\", function(event) {\n event.preventDefault();\n renderFilters($scope.filters[\"myFilters\"]);\n showFilters(\"My filters\", \"myFilters\");\n $el.find('.save-filters').hide();\n $el.find('.my-filter-name').removeClass(\"hidden\");\n return $el.find('.my-filter-name').focus();\n });\n return $el.on(\"keyup\", \".new .my-filter-name\", function(event) {\n var newFilter, promise, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newFilter = target.val();\n $loading.start($el.find(\".new\"));\n promise = $ctrl.saveCurrentFiltersTo(newFilter);\n promise.then(function() {\n var loadPromise;\n loadPromise = $ctrl.loadMyFilters();\n loadPromise.then(function(filters) {\n var currentfilterstype;\n $loading.finish($el.find(\".new\"));\n $scope.filters.myFilters = filters;\n currentfilterstype = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (currentfilterstype === \"myFilters\") {\n renderFilters($scope.filters.myFilters);\n }\n $el.find('.my-filter-name').addClass(\"hidden\");\n return $el.find('.save-filters').show();\n });\n return loadPromise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n return $confirm.notify(\"error\", \"Error loading custom filters\");\n });\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".my-filter-name\").val(newFilter).focus().select();\n return $confirm.notify(\"error\", \"Filter not saved\");\n });\n } else if (event.keyCode === 27) {\n $el.find('.my-filter-name').val('');\n $el.find('.my-filter-name').addClass(\"hidden\");\n return $el.find('.save-filters').show();\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssuesFilters\", [\"$log\", \"$tgLocation\", \"$tgResources\", \"$tgConfirm\", \"$tgLoading\", IssuesFiltersDirective]);\n\n IssueStatusInlineEditionDirective = function($repo, popoverService) {\n\n /*\n Print the status of an Issue and a popover to change it.\n - tg-issue-status-inline-edition: The issue\n \n Example:\n \n div.status(tg-issue-status-inline-edition=\"issue\")\n a.issue-status(href=\"\")\n \n NOTE: This directive need 'issueStatusById' and 'project'.\n */\n var link, selectionTemplate, updateIssueStatus;\n selectionTemplate = _.template(\"\");\n updateIssueStatus = function($el, issue, issueStatusById) {\n var issueStatusDom, issueStatusDomParent, status;\n issueStatusDomParent = $el.find(\".issue-status\");\n issueStatusDom = $el.find(\".issue-status .issue-status-bind\");\n status = issueStatusById[issue.status];\n if (status) {\n issueStatusDom.text(status.name);\n issueStatusDom.prop(\"title\", status.name);\n return issueStatusDomParent.css('color', status.color);\n }\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, issue;\n $ctrl = $el.controller();\n issue = $scope.$eval($attrs.tgIssueStatusInlineEdition);\n $el.on(\"click\", \".issue-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n issue.status = target.data(\"status-id\");\n $el.find(\".pop-status\").popover().close();\n updateIssueStatus($el, issue, $scope.issueStatusById);\n return $scope.$apply(function() {\n return $repo.save(issue).then;\n });\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n $el.append(selectionTemplate({\n 'statuses': project.issue_statuses\n }));\n updateIssueStatus($el, issue, $scope.issueStatusById);\n if (project.my_permissions.indexOf(\"modify_issue\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$watch($attrs.tgIssueStatusInlineEdition, (function(_this) {\n return function(val) {\n return updateIssueStatus($el, val, $scope.issueStatusById);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssueStatusInlineEdition\", [\"$tgRepo\", IssueStatusInlineEditionDirective]);\n\n IssueAssignedToInlineEditionDirective = function($repo, $rootscope, popoverService) {\n var link, template;\n template = _.template(\"\\\" alt=\\\"<%- name %>\\\"/>\\n
    <%- name %>
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, issue, updateIssue;\n updateIssue = function(issue) {\n var ctx, member;\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = $scope.usersById[issue.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name_display;\n }\n $el.find(\".avatar\").html(template(ctx));\n return $el.find(\".issue-assignedto\").attr('title', ctx.name);\n };\n $ctrl = $el.controller();\n issue = $scope.$eval($attrs.tgIssueAssignedToInlineEdition);\n updateIssue(issue);\n $el.on(\"click\", \".issue-assignedto\", function(event) {\n return $rootscope.$broadcast(\"assigned-to:add\", issue);\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_issue\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"assigned-to:added\", (function(_this) {\n return function(ctx, userId, updatedIssue) {\n if (updatedIssue.id === issue.id) {\n updatedIssue.assigned_to = userId;\n $repo.save(updatedIssue);\n return updateIssue(updatedIssue);\n }\n };\n })(this));\n $scope.$watch($attrs.tgIssueAssignedToInlineEdition, (function(_this) {\n return function(val) {\n return updateIssue(val);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssueAssignedToInlineEdition\", [\"$tgRepo\", \"$rootScope\", IssueAssignedToInlineEditionDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/userstories/detail.coffee\n */\n\n(function() {\n var UsClientRequirementButtonDirective, UsStatusButtonDirective, UsStatusDisplayDirective, UsTasksProgressDisplayDirective, UsTeamRequirementButtonDirective, UserStoryDetailController, bindOnce, groupBy, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaUserStories\");\n\n UserStoryDetailController = (function(_super) {\n __extends(UserStoryDetailController, _super);\n\n UserStoryDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function UserStoryDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.usRef = this.params.usref;\n this.scope.sectionName = \"User Story Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.us.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n UserStoryDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"related-tasks:update\", (function(_this) {\n return function() {\n _this.loadUs();\n return _this.scope.tasks = _.clone(_this.scope.tasks, false);\n };\n })(this));\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on userstory\", 1);\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n if (this.scope.project.is_backlog_activated) {\n if (this.scope.us.milestone) {\n ctx.sprint = this.scope.sprint.slug;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-taskboard\", ctx);\n } else {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-backlog\", ctx);\n }\n } else if (this.scope.project.is_kanban_activated) {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-kanban\", ctx);\n }\n };\n\n UserStoryDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.us_statuses;\n _this.scope.statusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.taskStatusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(_this.scope.pointsList, function(e) {\n return e.id;\n });\n return project;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadUs = function() {\n return this.rs.userstories.getByRef(this.scope.projectId, this.params.usref).then((function(_this) {\n return function(us) {\n var ctx;\n _this.scope.us = us;\n _this.scope.usId = us.id;\n _this.scope.commentModel = us;\n if (_this.scope.us.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.us.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n if (_this.scope.us.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.us.neighbors.next.ref\n };\n _this.scope.nextUrl = _this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n return us;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadSprint = function() {\n if (this.scope.us.milestone) {\n return this.rs.sprints.get(this.scope.us.project, this.scope.us.milestone).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n return sprint;\n };\n })(this));\n }\n };\n\n UserStoryDetailController.prototype.loadTasks = function() {\n return this.rs.tasks.list(this.scope.projectId, null, this.scope.usId).then((function(_this) {\n return function(tasks) {\n _this.scope.tasks = tasks;\n return tasks;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadUs().then(function() {\n return _this.q.all([_this.loadSprint(), _this.loadTasks()]);\n });\n };\n })(this));\n };\n\n return UserStoryDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserStoryDetailController\", UserStoryDetailController);\n\n UsStatusDisplayDirective = function() {\n var link, template;\n template = _.template(\"\\n <% if (is_closed) { %>\\n Closed\\n <% } else { %>\\n Open\\n <% } %>\\n\\n\\\">\\n <%- status.name %>\\n\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function(us) {\n var html;\n html = template({\n is_closed: us.is_closed,\n status: $scope.statusById[us.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(us) {\n if (us != null) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsStatusDisplay\", UsStatusDisplayDirective);\n\n UsTasksProgressDisplayDirective = function() {\n var link, template;\n template = _.template(\"
    %\\\" />\\n\\n <%- totalClosedTasks %>/<%- totalTasks %> tasks completed\\n\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function(tasks) {\n var html, progress, totalClosedTasks, totalTasks;\n totalTasks = tasks.length;\n totalClosedTasks = _.filter(tasks, (function(_this) {\n return function(task) {\n return $scope.taskStatusById[task.status].is_closed;\n };\n })(this)).length;\n progress = totalTasks > 0 ? 100 * totalClosedTasks / totalTasks : 0;\n html = template({\n totalTasks: totalTasks,\n totalClosedTasks: totalClosedTasks,\n progress: progress\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(tasks) {\n if (tasks != null) {\n return render(tasks);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsTasksProgressDisplay\", UsTasksProgressDisplayDirective);\n\n UsStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- status.name %>\\n <% if(editable){ %><% }%>\\n status\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = (function(_this) {\n return function(us) {\n var html, status;\n status = $scope.statusById[us.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(status) {\n var onError, onSuccess, us;\n us = $model.$modelValue.clone();\n us.status = status;\n $.fn.popover().closeAll();\n $model.$setViewValue(us);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n us.revert();\n $model.$setViewValue(us);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var status, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n status = target.data(\"status-id\");\n return save(status);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", UsStatusButtonDirective]);\n\n UsTeamRequirementButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"\\n\");\n link = function($scope, $el, $attrs, $model) {\n var canEdit, render, save;\n canEdit = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var ctx, html;\n if (!canEdit() && !us.team_requirement) {\n $el.html(\"\");\n return;\n }\n ctx = {\n canEdit: canEdit(),\n isRequired: us.team_requirement\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(team_requirement) {\n var promise, us;\n us = $model.$modelValue.clone();\n us.team_requirement = team_requirement;\n $model.$setViewValue(us);\n $loading.start($el.find(\"label\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el.find(\"label\"));\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\"label\"));\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n });\n };\n })(this));\n $el.on(\"click\", \".team-requirement\", function(event) {\n var team_requirement;\n if (!canEdit()) {\n return;\n }\n team_requirement = !$model.$modelValue.team_requirement;\n return save(team_requirement);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsTeamRequirementButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", UsTeamRequirementButtonDirective]);\n\n UsClientRequirementButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"\\n\");\n link = function($scope, $el, $attrs, $model) {\n var canEdit, render, save;\n canEdit = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var ctx, html;\n if (!canEdit() && !us.client_requirement) {\n $el.html(\"\");\n return;\n }\n ctx = {\n canEdit: canEdit(),\n isRequired: us.client_requirement\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(client_requirement) {\n var promise, us;\n us = $model.$modelValue.clone();\n us.client_requirement = client_requirement;\n $model.$setViewValue(us);\n $loading.start($el.find(\"label\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el.find(\"label\"));\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\"label\"));\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n });\n };\n })(this));\n $el.on(\"click\", \".client-requirement\", function(event) {\n var client_requirement;\n if (!canEdit()) {\n return;\n }\n client_requirement = !$model.$modelValue.client_requirement;\n return save(client_requirement);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsClientRequirementButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", UsClientRequirementButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/tasks/detail.coffee\n */\n\n(function() {\n var TaskDetailController, TaskIsIocaineButtonDirective, TaskStatusButtonDirective, TaskStatusDisplayDirective, groupBy, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaTasks\");\n\n TaskDetailController = (function(_super) {\n __extends(TaskDetailController, _super);\n\n TaskDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function TaskDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.taskRef = this.params.taskref;\n this.scope.sectionName = \"Task Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.task.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TaskDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on task\", 1);\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n };\n\n TaskDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n if (this.scope.project.is_backlog_activated) {\n if (this.scope.task.milestone) {\n ctx.sprint = this.scope.sprint.slug;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-taskboard\", ctx);\n } else if (this.scope.task.us) {\n ctx.ref = this.scope.us.ref;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n } else if (this.scope.project.is_kanban_activated) {\n if (this.scope.us) {\n ctx.ref = this.scope.us.ref;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n }\n };\n\n TaskDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.task_statuses;\n _this.scope.statusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n TaskDetailController.prototype.loadTask = function() {\n return this.rs.tasks.getByRef(this.scope.projectId, this.params.taskref).then((function(_this) {\n return function(task) {\n var ctx;\n _this.scope.task = task;\n _this.scope.taskId = task.id;\n _this.scope.commentModel = task;\n if (_this.scope.task.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.task.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-tasks-detail\", ctx);\n }\n if (_this.scope.task.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.task.neighbors.next.ref\n };\n _this.scope.nextUrl = _this.navUrls.resolve(\"project-tasks-detail\", ctx);\n }\n return task;\n };\n })(this));\n };\n\n TaskDetailController.prototype.loadSprint = function() {\n if (this.scope.task.milestone) {\n return this.rs.sprints.get(this.scope.task.project, this.scope.task.milestone).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n return sprint;\n };\n })(this));\n }\n };\n\n TaskDetailController.prototype.loadUserStory = function() {\n if (this.scope.task.user_story) {\n return this.rs.userstories.get(this.scope.task.project, this.scope.task.user_story).then((function(_this) {\n return function(us) {\n _this.scope.us = us;\n return us;\n };\n })(this));\n }\n };\n\n TaskDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadTask().then(function() {\n return _this.q.all([_this.loadSprint(), _this.loadUserStory()]);\n });\n };\n })(this));\n };\n\n return TaskDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TaskDetailController\", TaskDetailController);\n\n TaskStatusDisplayDirective = function() {\n var link, template;\n template = _.template(\"\\n <% if (status.is_closed) { %>\\n Closed\\n <% } else { %>\\n Open\\n <% } %>\\n\\n\\\">\\n <%- status.name %>\\n\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function(task) {\n var html;\n html = template({\n status: $scope.statusById[task.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(task) {\n if (task != null) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskStatusDisplay\", TaskStatusDisplayDirective);\n\n TaskStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- status.name %>\\n <% if(editable){ %><% }%>\\n status\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_task\") !== -1;\n };\n render = (function(_this) {\n return function(task) {\n var html, status;\n status = $scope.statusById[task.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(status) {\n var onError, onSuccess, task;\n task = $model.$modelValue.clone();\n task.status = status;\n $model.$setViewValue(task);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n task.revert();\n $model.$setViewValue(task);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n $.fn.popover().closeAll();\n return save(target.data(\"status-id\"));\n });\n $scope.$watch($attrs.ngModel, function(task) {\n if (task) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", TaskStatusButtonDirective]);\n\n TaskIsIocaineButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    \\n \\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_task\") !== -1;\n };\n render = function(task) {\n var ctx, html;\n if (!isEditable() && !task.is_iocaine) {\n $el.html(\"\");\n return;\n }\n ctx = {\n isIocaine: task.is_iocaine,\n isEditable: isEditable()\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(is_iocaine) {\n var promise, task;\n task = $model.$modelValue.clone();\n task.is_iocaine = is_iocaine;\n $model.$setViewValue(task);\n $loading.start($el.find('label'));\n promise = $tgrepo.save(task);\n promise.then(function() {\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n task.revert();\n $model.$setViewValue(task);\n return $confirm.notify(\"error\");\n });\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('label'));\n });\n };\n })(this));\n $el.on(\"click\", \".is-iocaine\", function(event) {\n var is_iocaine;\n if (!isEditable()) {\n return;\n }\n is_iocaine = !$model.$modelValue.is_iocaine;\n return save(is_iocaine);\n });\n $scope.$watch($attrs.ngModel, function(task) {\n if (task) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskIsIocaineButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", TaskIsIocaineButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/team/main.coffee\n */\n\n(function() {\n var LeaveProjectDirective, TeamController, TeamFiltersDirective, TeamMemberCurrentUserDirective, TeamMemberStatsDirective, TeamMembersDirective, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n module = angular.module(\"taigaTeam\");\n\n TeamController = (function(_super) {\n __extends(TeamController, _super);\n\n TeamController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$q\", \"$location\", \"$tgNavUrls\", \"$appTitle\", \"$tgAuth\", \"tgLoader\"];\n\n function TeamController(scope, rootscope, repo, rs, params, q, location, navUrls, appTitle, auth, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.auth = auth;\n this.scope.sectionName = \"Team\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Team - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TeamController.prototype.setRole = function(role) {\n if (role) {\n return this.scope.filtersRole = role;\n } else {\n return this.scope.filtersRole = \"\";\n }\n };\n\n TeamController.prototype.loadMembers = function() {\n return this.rs.memberships.list(this.scope.projectId, {}, false).then((function(_this) {\n return function(data) {\n var currentUser, membership, _i, _len, _ref;\n currentUser = _this.auth.getUser();\n if (currentUser.photo == null) {\n currentUser.photo = \"/images/unnamed.png\";\n }\n _this.scope.currentUser = _.find(data, function(membership) {\n return membership.user === currentUser.id;\n });\n _this.scope.totals = {};\n _.forEach(data, function(membership) {\n return _this.scope.totals[membership.user] = 0;\n });\n _this.scope.memberships = _.filter(data, function(membership) {\n if (membership.user && membership.user !== currentUser.id && membership.is_user_active) {\n return membership;\n }\n });\n _ref = _this.scope.memberships;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n membership = _ref[_i];\n if (membership.photo == null) {\n membership.photo = \"/images/unnamed.png\";\n }\n }\n return data;\n };\n })(this));\n };\n\n TeamController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issuesEnabled = project.is_issues_activated;\n _this.scope.tasksEnabled = project.is_kanban_activated || project.is_backlog_activated;\n _this.scope.wikiEnabled = project.is_wiki_activated;\n return project;\n };\n })(this));\n };\n\n TeamController.prototype.loadMemberStats = function() {\n return this.rs.projects.memberStats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n var totals;\n totals = {};\n _.forEach(_this.scope.totals, function(total, userId) {\n var vals;\n vals = _.map(stats, function(memberStats, statsKey) {\n return memberStats[userId];\n });\n total = _.reduce(vals, function(sum, el) {\n return sum + el;\n });\n return _this.scope.totals[userId] = total;\n });\n _this.scope.stats = _this.processStats(stats);\n return _this.scope.stats.totals = _this.scope.totals;\n };\n })(this));\n };\n\n TeamController.prototype.processStat = function(stat) {\n var max, min, singleStat;\n max = _.max(stat);\n min = _.min(stat);\n singleStat = _.map(stat, function(value, key) {\n if (value === min) {\n return [key, 0.1];\n }\n if (value === max) {\n return [key, 1];\n }\n return [key, (value * 0.5) / max];\n });\n singleStat = _.object(singleStat);\n return singleStat;\n };\n\n TeamController.prototype.processStats = function(stats) {\n var key, value;\n for (key in stats) {\n value = stats[key];\n stats[key] = this.processStat(value);\n }\n return stats;\n };\n\n TeamController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadMembers().then(function() {\n return _this.loadMemberStats();\n });\n };\n })(this));\n };\n\n return TeamController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TeamController\", TeamController);\n\n TeamFiltersDirective = function() {\n var template;\n template = \"\";\n return {\n template: template\n };\n };\n\n module.directive(\"tgTeamFilters\", [TeamFiltersDirective]);\n\n TeamMemberStatsDirective = function() {\n var template;\n template = \"
    \\n \\n
    \\n
    \\n \\n
    \\n
    \\n \\n
    \\n
    \\n \\n
    \\n
    \\n \\n
    \\n
    \\n \\n
    \";\n return {\n template: template,\n scope: {\n stats: \"=\",\n userId: \"=user\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamMemberStats\", TeamMemberStatsDirective);\n\n TeamMemberCurrentUserDirective = function() {\n var template;\n template = \"
    \\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \";\n return {\n template: template,\n scope: {\n projectId: \"=projectid\",\n currentUser: \"=currentuser\",\n stats: \"=\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamCurrentUser\", TeamMemberCurrentUserDirective);\n\n TeamMembersDirective = function() {\n var template;\n template = \"
    \\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n
    \";\n return {\n template: template,\n scope: {\n memberships: \"=\",\n filtersQ: \"=filtersq\",\n filtersRole: \"=filtersrole\",\n stats: \"=\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamMembers\", TeamMembersDirective);\n\n LeaveProjectDirective = function($repo, $confirm, $location, $rs, $navurls) {\n var link, template;\n template = \"\\n Leave this project\\n\";\n link = function($scope, $el, $attrs) {\n return $scope.leave = function() {\n return $confirm.ask(\"Leave this project\", \"Are you sure you want to leave the project?\").then((function(_this) {\n return function(finish) {\n var promise;\n promise = $rs.projects.leave($attrs.projectid);\n promise.then(function() {\n finish();\n $confirm.notify(\"success\");\n return $location.path($navurls.resolve(\"home\"));\n });\n return promise.then(null, function(response) {\n finish();\n return $confirm.notify('error', response.data._error_message);\n });\n };\n })(this));\n };\n };\n return {\n scope: {},\n template: template,\n link: link\n };\n };\n\n module.directive(\"tgLeaveProject\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", \"$tgResources\", \"$tgNavUrls\", LeaveProjectDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki/detail.coffee\n */\n\n(function() {\n var EditableWikiContentDirective, WikiDetailController, WikiSummaryDirective, bindOnce, debounce, groupBy, mixOf, module, taiga, unslugify,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n unslugify = this.taiga.unslugify;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaWiki\");\n\n WikiDetailController = (function(_super) {\n __extends(WikiDetailController, _super);\n\n WikiDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgModel\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$filter\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function WikiDetailController(scope, rootscope, repo, model, confirm, rs, params, q, location, filter, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.model = model;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.filter = filter;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.projectSlug = this.params.pslug;\n this.scope.wikiSlug = this.params.slug;\n this.scope.sectionName = \"Wiki\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Wiki - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n WikiDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadWiki = function() {\n var promise;\n promise = this.rs.wiki.getBySlug(this.scope.projectId, this.params.slug);\n promise.then((function(_this) {\n return function(wiki) {\n _this.scope.wiki = wiki;\n _this.scope.wikiId = wiki.id;\n return _this.scope.wiki;\n };\n })(this));\n return promise.then(null, (function(_this) {\n return function(xhr) {\n var data;\n _this.scope.wikiId = null;\n if (_this.scope.project.my_permissions.indexOf(\"add_wiki_page\") === -1) {\n return null;\n }\n data = {\n project: _this.scope.projectId,\n slug: _this.scope.wikiSlug,\n content: \"\"\n };\n _this.scope.wiki = _this.model.make_model(\"wiki\", data);\n return _this.scope.wiki;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadWikiLinks = function() {\n return this.rs.wiki.listLinks(this.scope.projectId).then((function(_this) {\n return function(wikiLinks) {\n return _this.scope.wikiLinks = wikiLinks;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.q.all([_this.loadWikiLinks(), _this.loadWiki()]);\n };\n })(this));\n };\n\n WikiDetailController.prototype[\"delete\"] = function() {\n var message, title;\n title = \"Delete Wiki Page\";\n message = unslugify(this.scope.wiki.slug);\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n var ctx;\n finish();\n ctx = {\n project: _this.scope.projectSlug\n };\n _this.location.path(_this.navUrls.resolve(\"project-wiki\", ctx));\n return _this.confirm.notify(\"success\");\n };\n onError = function() {\n finish(false);\n return _this.confirm.notify(\"error\");\n };\n return _this.repo.remove(_this.scope.wiki).then(onSuccess, onError);\n };\n })(this));\n };\n\n return WikiDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"WikiDetailController\", WikiDetailController);\n\n WikiSummaryDirective = function($log) {\n var link, template;\n template = _.template(\"
      \\n
    • \\n <%- totalEditions %>\\n times
      edited
      \\n
    • \\n
    • \\n <%- lastModifiedDate %>\\n last
      edit
      \\n
    • \\n
    • \\n
      \\n \\\" alt=\\\"<%- user.name %>\\\">\\n
      \\n last modification\\n <%- user.name %>\\n
    • \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var render;\n render = function(wiki) {\n var ctx, html, user;\n if ($scope.usersById == null) {\n $log.error(\"WikiSummaryDirective requires userById set in scope.\");\n } else {\n user = $scope.usersById[wiki.last_modifier];\n }\n if (user === void 0) {\n user = {\n name: \"unknown\",\n imgUrl: \"/images/unnamed.png\"\n };\n } else {\n user = {\n name: user.full_name_display,\n imgUrl: user.photo\n };\n }\n ctx = {\n totalEditions: wiki.editions,\n lastModifiedDate: moment(wiki.modified_date).format(\"DD MMM YYYY HH:mm\"),\n user: user\n };\n html = template(ctx);\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(wikiPage) {\n if (!wikiPage) {\n return;\n }\n return render(wikiPage);\n });\n $scope.$on(\"wiki:edit\", function(event, wikiPage) {\n return render(wikiPage);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgWikiSummary\", [\"$log\", WikiSummaryDirective]);\n\n EditableWikiContentDirective = function($window, $document, $repo, $confirm, $loading, $location, $navUrls, $analytics, $qqueue) {\n var link, template;\n template = \"
    \\n
    \\n \\n
    \\n\";\n link = function($scope, $el, $attrs, $model) {\n var cancelEdition, disableEdition, getSelectedText, isEditable, save, switchToEditMode, switchToReadMode;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_wiki_page\") !== -1;\n };\n switchToEditMode = function() {\n $el.find('.edit-wiki-content').show();\n $el.find('.view-wiki-content').hide();\n return $el.find('textarea').focus();\n };\n switchToReadMode = function() {\n $el.find('.edit-wiki-content').hide();\n return $el.find('.view-wiki-content').show();\n };\n disableEdition = function() {\n $el.find(\".view-wiki-content .edit\").remove();\n return $el.find(\".edit-wiki-content\").remove();\n };\n cancelEdition = function() {\n var ctx;\n if (!$scope.wiki.html) {\n return;\n }\n if ($scope.wiki.id) {\n $scope.$apply((function(_this) {\n return function() {\n return $scope.wiki.revert();\n };\n })(this));\n return switchToReadMode();\n } else {\n ctx = {\n project: $scope.projectSlug\n };\n return $location.path($navUrls.resolve(\"project-wiki\", ctx));\n }\n };\n getSelectedText = function() {\n if ($window.getSelection) {\n return $window.getSelection().toString();\n } else if ($document.selection) {\n return $document.selection.createRange().text;\n }\n return null;\n };\n save = $qqueue.bindAdd(function(wiki) {\n var onError, onSuccess, promise;\n onSuccess = function(wikiPage) {\n if (wiki.id == null) {\n $analytics.trackEvent(\"wikipage\", \"create\", \"create wiki page\", 1);\n }\n $scope.wiki = wikiPage;\n $model.setModelValue = wiki;\n $confirm.notify(\"success\");\n switchToReadMode();\n return $scope.$broadcast(\"wiki:edit\", wikiPage);\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n $loading.start($el.find('.save-container'));\n if (wiki.id != null) {\n promise = $repo.save(wiki).then(onSuccess, onError);\n } else {\n promise = $repo.create(\"wiki\", wiki).then(onSuccess, onError);\n }\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n });\n $el.on(\"mousedown\", \".view-wiki-content\", function(event) {\n var target;\n target = angular.element(event.target);\n if (target.is('pre')) {\n return target.data(\"scroll-pos\", target[0].scrollLeft);\n }\n });\n $el.on(\"mouseup\", \".view-wiki-content\", function(event) {\n var prevPos, target;\n target = angular.element(event.target);\n if (!isEditable()) {\n return;\n }\n if (target.is('a')) {\n return;\n }\n if (getSelectedText()) {\n return;\n }\n if (target.is('pre')) {\n prevPos = target.data(\"scroll-pos\");\n target.data(\"scroll-pos\", null);\n if (prevPos !== target[0].scrollLeft) {\n return;\n }\n }\n return switchToEditMode();\n });\n $el.on(\"click\", \".save\", debounce(2000, function() {\n return save($scope.wiki);\n }));\n $el.on(\"click\", \".cancel\", function() {\n return cancelEdition();\n });\n $el.on(\"keydown\", \"textarea\", function(event) {\n if (event.keyCode === 27) {\n return cancelEdition();\n }\n });\n $scope.$watch($attrs.ngModel, function(wikiPage) {\n if (!wikiPage) {\n return;\n }\n $scope.wiki = wikiPage;\n if (isEditable()) {\n $el.addClass('editable');\n if (wikiPage.id == null) {\n return switchToEditMode();\n }\n } else {\n return disableEdition();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgEditableWikiContent\", [\"$window\", \"$document\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAnalytics\", \"$tgQqueue\", EditableWikiContentDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki/detail.coffee\n */\n\n(function() {\n var WikiNavDirective, bindOnce, groupBy, mixOf, module, slugify, taiga, unslugify;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n slugify = this.taiga.slugify;\n\n unslugify = this.taiga.slugify;\n\n module = angular.module(\"taigaWiki\");\n\n WikiNavDirective = function($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $loading) {\n var link, template;\n template = _.template(\"
    \\n

    Links

    \\n
    \\n
    \\n<% if (addWikiLinkPermission) { %>\\nAdd link\\n<% } %>\");\n link = function($scope, $el, $attrs) {\n var $ctrl, render;\n $ctrl = $el.controller();\n if ($attrs.ngModel == null) {\n return $log.error(\"WikiNavDirective: no ng-model attr is defined\");\n }\n render = function(wikiLinks) {\n var addWikiLinkPermission, deleteWikiLinkPermission, html;\n addWikiLinkPermission = $scope.project.my_permissions.indexOf(\"add_wiki_link\") > -1;\n deleteWikiLinkPermission = $scope.project.my_permissions.indexOf(\"delete_wiki_link\") > -1;\n html = template({\n wikiLinks: wikiLinks,\n projectSlug: $scope.projectSlug,\n addWikiLinkPermission: addWikiLinkPermission,\n deleteWikiLinkPermission: deleteWikiLinkPermission\n });\n $el.off();\n $el.html(html);\n $el.on(\"click\", \".wiki-link .link-title\", function(event) {\n var linkId, linkSlug, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n linkId = target.parents('.wiki-link').data('id');\n linkSlug = $scope.wikiLinks[linkId].href;\n return $scope.$apply(function() {\n var ctx;\n ctx = {\n project: $scope.projectSlug,\n slug: linkSlug\n };\n return $location.path($navUrls.resolve(\"project-wiki-page\", ctx));\n });\n });\n $el.on(\"click\", \".add-button\", function(event) {\n event.preventDefault();\n $el.find(\".new\").removeClass(\"hidden\");\n $el.find(\".new input\").focus();\n return $el.find(\".add-button\").hide();\n });\n $el.on(\"click\", \".wiki-link .icon-delete\", function(event) {\n var linkId, message, target, title;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n linkId = target.parents('.wiki-link').data('id');\n title = \"Delete Wiki Link\";\n message = $scope.wikiLinks[linkId].title;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var promise;\n promise = $tgrepo.remove($scope.wikiLinks[linkId]);\n promise.then(function() {\n promise = $ctrl.loadWikiLinks();\n promise.then(function() {\n finish();\n return render($scope.wikiLinks);\n });\n return promise.then(null, function() {\n return finish();\n });\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n });\n return $el.on(\"keyup\", \".new input\", function(event) {\n var newLink, promise, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newLink = target.val();\n $loading.start($el.find(\".new\"));\n promise = $tgrepo.create(\"wiki-links\", {\n project: $scope.projectId,\n title: newLink,\n href: slugify(newLink)\n });\n promise.then(function() {\n var loadPromise;\n $analytics.trackEvent(\"wikilink\", \"create\", \"create wiki link\", 1);\n loadPromise = $ctrl.loadWikiLinks();\n loadPromise.then(function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n $el.find(\".add-button\").show();\n return render($scope.wikiLinks);\n });\n return loadPromise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n $el.find(\".add-button\").show();\n return $confirm.notify(\"error\", \"Error loading wiki links\");\n });\n });\n return promise.then(null, function(error) {\n var _ref;\n $loading.finish($el.find(\".new\"));\n $el.find(\".new input\").val(newLink);\n $el.find(\".new input\").focus().select();\n if ((error != null ? (_ref = error.__all__) != null ? _ref[0] : void 0 : void 0) != null) {\n return $confirm.notify(\"error\", \"The link already exists\");\n } else {\n return $confirm.notify(\"error\");\n }\n });\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n return $el.find(\".add-button\").show();\n }\n });\n };\n return bindOnce($scope, $attrs.ngModel, render);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgWikiNav\", [\"$tgRepo\", \"$log\", \"$tgLocation\", \"$tgConfirm\", \"$tgNavUrls\", \"$tgAnalytics\", \"$tgLoading\", WikiNavDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/lightboxes.coffee\n */\n\n(function() {\n var CreateMembersDirective, MAX_MEMBERSHIP_FIELDSETS, debounce, module, taiga;\n\n taiga = this.taiga;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaKanban\");\n\n MAX_MEMBERSHIP_FIELDSETS = 4;\n\n CreateMembersDirective = function($rs, $rootScope, $confirm, $loading, lightboxService) {\n var extraTextTemplate, link, template;\n extraTextTemplate = \"
    \\n \\n
    \";\n template = _.template(\"
    \\n
    \\n data-required=\\\"true\\\" <% } %> data-type=\\\"email\\\" />\\n
    \\n
    \\n \\n \\n
    \\n
    \");\n link = function($scope, $el, $attrs) {\n var createFieldSet, resetForm, submit, submitButton;\n createFieldSet = function(required) {\n var ctx;\n if (required == null) {\n required = true;\n }\n ctx = {\n roleList: $scope.roles,\n required: required\n };\n return template(ctx);\n };\n resetForm = function() {\n var fieldSet, invitations;\n $el.find(\"form textarea\").remove(\"\");\n $el.find(\"form .add-member-wrapper\").remove();\n invitations = $el.find(\".add-member-forms\");\n invitations.html(extraTextTemplate);\n fieldSet = createFieldSet();\n return invitations.prepend(fieldSet);\n };\n $scope.$on(\"membersform:new\", function() {\n resetForm();\n return lightboxService.open($el);\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $el.on(\"click\", \".delete-fieldset\", function(event) {\n var fieldSet, lastActionButton, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n fieldSet = target.closest('.add-member-wrapper');\n fieldSet.remove();\n lastActionButton = $el.find(\"fieldset:last > a\");\n if (lastActionButton.hasClass(\"icon-delete delete-fieldset\")) {\n return lastActionButton.removeClass(\"icon-delete delete-fieldset\").addClass(\"icon-plus add-fieldset\");\n }\n });\n $el.on(\"click\", \".add-fieldset\", function(event) {\n var fieldSet, newFieldSet, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n fieldSet = target.closest('.add-member-wrapper');\n target.removeClass(\"icon-plus add-fieldset\").addClass(\"icon-delete delete-fieldset\");\n newFieldSet = createFieldSet(false);\n fieldSet.after(newFieldSet);\n if ($el.find(\".add-member-wrapper\").length === MAX_MEMBERSHIP_FIELDSETS) {\n return $el.find(\".add-member-wrapper fieldset:last > a\").removeClass(\"icon-plus add-fieldset\").addClass(\"icon-delete delete-fieldset\");\n }\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, invitation_extra_text, invitations, memberWrappers, onError, onSuccess;\n event.preventDefault();\n $loading.start(submitButton);\n onSuccess = function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"membersform:new:success\");\n };\n onError = function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n $confirm.notify(\"error\");\n return $rootScope.$broadcast(\"membersform:new:error\");\n };\n form = $el.find(\"form\").checksley();\n form.destroy();\n form.initialize();\n if (!form.validate()) {\n return;\n }\n memberWrappers = $el.find(\"form .add-member-wrapper\");\n memberWrappers = _.filter(memberWrappers, function(mw) {\n return angular.element(mw).find(\"input\").hasClass('checksley-ok');\n });\n invitations = _.map(memberWrappers, function(mw) {\n var email, memberWrapper, role;\n memberWrapper = angular.element(mw);\n email = memberWrapper.find(\"input\");\n role = memberWrapper.find(\"select\");\n return {\n email: email.val(),\n role_id: role.val()\n };\n });\n if (invitations.length) {\n invitation_extra_text = $el.find(\"form textarea\").val();\n return $rs.memberships.bulkCreateMemberships($scope.project.id, invitations, invitation_extra_text).then(onSuccess, onError);\n }\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateMembers\", [\"$tgResources\", \"$rootScope\", \"$tgConfirm\", \"$tgLoading\", \"lightboxService\", CreateMembersDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/memberships.coffee\n */\n\n(function() {\n var MembershipsController, MembershipsDirective, MembershipsRowActionsDirective, MembershipsRowAdminCheckboxDirective, MembershipsRowAvatarDirective, MembershipsRowRoleSelectorDirective, bindMethods, mixOf, module, paginatorTemplate, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaAdmin\");\n\n MembershipsController = (function(_super) {\n __extends(MembershipsController, _super);\n\n MembershipsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAnalytics\", \"$appTitle\"];\n\n function MembershipsController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, analytics, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Manage Members\";\n this.scope.project = {};\n this.scope.filters = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Membership - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"membersform:new:success\", (function(_this) {\n return function() {\n _this.loadMembers();\n return _this.analytics.trackEvent(\"membership\", \"create\", \"create memberships on admin\", 1);\n };\n })(this));\n }\n\n MembershipsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n MembershipsController.prototype.loadMembers = function() {\n var httpFilters;\n httpFilters = this.getUrlFilters();\n return this.rs.memberships.list(this.scope.projectId, httpFilters).then((function(_this) {\n return function(data) {\n _this.scope.memberships = _.filter(data.models, function(membership) {\n return membership.user === null || membership.is_user_active;\n });\n _this.scope.page = data.current;\n _this.scope.count = data.count;\n _this.scope.paginatedBy = data.paginatedBy;\n return data;\n };\n })(this));\n };\n\n MembershipsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadMembers();\n };\n })(this));\n };\n\n MembershipsController.prototype.getUrlFilters = function() {\n var filters;\n filters = _.pick(this.location.search(), \"page\");\n if (!filters.page) {\n filters.page = 1;\n }\n return filters;\n };\n\n MembershipsController.prototype.addNewMembers = function() {\n return this.rootscope.$broadcast(\"membersform:new\");\n };\n\n return MembershipsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"MembershipsController\", MembershipsController);\n\n paginatorTemplate = \"
      \\n <% if (showPrevious) { %>\\n
    • \\n \\n Prev\\n \\n
    • \\n <% } %>\\n\\n <% _.each(pages, function(item) { %>\\n
    • \\\">\\n <% if (item.type === \\\"page\\\") { %>\\n \\\"><%- item.num %>\\n <% } else if (item.type === \\\"page-active\\\") { %>\\n <%- item.num %>\\n <% } else { %>\\n ...\\n <% } %>\\n
    • \\n <% }); %>\\n\\n <% if (showNext) { %>\\n
    • \\n \\n Next\\n \\n
    • \\n <% } %>\\n
    \";\n\n MembershipsDirective = function() {\n var link, linkPagination, template;\n template = _.template(paginatorTemplate);\n linkPagination = function($scope, $el, $attrs, $ctrl) {\n var $pagEl, afterCurrent, atBegin, atEnd, beforeCurrent, getNumPages, renderPagination;\n afterCurrent = 2;\n beforeCurrent = 4;\n atBegin = 2;\n atEnd = 2;\n $pagEl = $el.find(\".memberships-paginator\");\n getNumPages = function() {\n var numPages;\n numPages = $scope.count / $scope.paginatedBy;\n if (parseInt(numPages, 10) < numPages) {\n numPages = parseInt(numPages, 10) + 1;\n } else {\n numPages = parseInt(numPages, 10);\n }\n return numPages;\n };\n renderPagination = function() {\n var cpage, i, numPages, options, pages, _i;\n numPages = getNumPages();\n if (numPages <= 1) {\n $pagEl.hide();\n return;\n }\n pages = [];\n options = {};\n options.pages = pages;\n options.showPrevious = $scope.page > 1;\n options.showNext = !($scope.page === numPages);\n cpage = $scope.page;\n for (i = _i = 1; 1 <= numPages ? _i <= numPages : _i >= numPages; i = 1 <= numPages ? ++_i : --_i) {\n if (i === (cpage + afterCurrent) && numPages > (cpage + afterCurrent + atEnd)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i === (cpage - beforeCurrent) && cpage > (atBegin + beforeCurrent)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i > (cpage + afterCurrent) && i <= (numPages - atEnd)) {\n\n } else if (i < (cpage - beforeCurrent) && i > atBegin) {\n\n } else if (i === cpage) {\n pages.push({\n classes: \"active\",\n num: i,\n type: \"page-active\"\n });\n } else {\n pages.push({\n classes: \"page\",\n num: i,\n type: \"page\"\n });\n }\n }\n return $pagEl.html(template(options));\n };\n $scope.$watch(\"memberships\", function(value) {\n if (!value) {\n return;\n }\n return renderPagination();\n });\n $el.on(\"click\", \".memberships-paginator a.next\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page + 1);\n return $ctrl.loadMembers();\n });\n });\n $el.on(\"click\", \".memberships-paginator a.previous\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page - 1);\n return $ctrl.loadMembers();\n });\n });\n return $el.on(\"click\", \".memberships-paginator li.page > a\", function(event) {\n var pagenum, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n pagenum = target.data(\"pagenum\");\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", pagenum);\n return $ctrl.loadMembers();\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n linkPagination($scope, $el, $attrs, $ctrl);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMemberships\", MembershipsDirective);\n\n MembershipsRowAvatarDirective = function($log) {\n var link, template;\n template = _.template(\"
    \\n \\\" alt=\\\"<%- full_name %>\\\">\\n
    \\n <%- full_name %>\\n <%- email %>\\n
    \\n
    \");\n link = function($scope, $el, $attrs) {\n var member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n full_name: member.full_name ? member.full_name : \"\",\n email: member.user_email ? member.user_email : member.email,\n imgurl: member.photo ? member.photo : \"/images/unnamed.png\"\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowAvatar == null) {\n return $log.error(\"MembershipsRowAvatarDirective: the directive need a member\");\n }\n member = $scope.$eval($attrs.tgMembershipsRowAvatar);\n render(member);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowAvatar\", [\"$log\", MembershipsRowAvatarDirective]);\n\n MembershipsRowAdminCheckboxDirective = function($log, $repo, $confirm) {\n var link, template;\n template = _.template(\"
    \\n \\\" />\\n
    \\n Yes\\n No\\n
    \");\n link = function($scope, $el, $attrs) {\n var html, member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n inputId: \"is-admin-\" + member.id\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowAdminCheckbox == null) {\n return $log.error(\"MembershipsRowAdminCheckboxDirective: the directive need a member\");\n }\n member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox);\n html = render(member);\n if (member.is_owner) {\n $el.find(\":checkbox\").prop(\"checked\", true);\n }\n $el.on(\"click\", \":checkbox\", (function(_this) {\n return function(event) {\n var onError, onSuccess, target;\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function(data) {\n member.revert();\n $el.find(\":checkbox\").prop(\"checked\", member.is_owner);\n return $confirm.notify(\"error\", data.is_owner[0]);\n };\n target = angular.element(event.currentTarget);\n member.is_owner = target.prop(\"checked\");\n return $repo.save(member).then(onSuccess, onError);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowAdminCheckbox\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", MembershipsRowAdminCheckboxDirective]);\n\n MembershipsRowRoleSelectorDirective = function($log, $repo, $confirm) {\n var link, template;\n template = _.template(\"\");\n link = function($scope, $el, $attrs) {\n var $ctrl, html, member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n roleList: $scope.roles,\n selectedRole: member.role\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowRoleSelector == null) {\n return $log.error(\"MembershipsRowRoleSelectorDirective: the directive need a member\");\n }\n $ctrl = $el.controller();\n member = $scope.$eval($attrs.tgMembershipsRowRoleSelector);\n html = render(member);\n $el.on(\"click\", \"select\", (function(_this) {\n return function(event) {\n var newRole, onError, onSuccess, target;\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n target = angular.element(event.currentTarget);\n newRole = parseInt(target.val(), 10);\n if (member.role !== newRole) {\n member.role = newRole;\n return $repo.save(member).then(onSuccess, onError);\n }\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowRoleSelector\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", MembershipsRowRoleSelectorDirective]);\n\n MembershipsRowActionsDirective = function($log, $repo, $rs, $confirm) {\n var activedTemplate, link, pendingTemplate;\n activedTemplate = _.template(\"
    \\n Active\\n
    \\n\\n \\n\");\n pendingTemplate = _.template(\"\\n Pending\\n \\n\\n\\n \\n\");\n link = function($scope, $el, $attrs) {\n var $ctrl, member, render;\n render = function(member) {\n var html;\n if (member.user) {\n html = activedTemplate();\n } else {\n html = pendingTemplate();\n }\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowActions == null) {\n return $log.error(\"MembershipsRowActionsDirective: the directive need a member\");\n }\n $ctrl = $el.controller();\n member = $scope.$eval($attrs.tgMembershipsRowActions);\n render(member);\n $el.on(\"click\", \".pending\", function(event) {\n var onError, onSuccess;\n event.preventDefault();\n onSuccess = function() {\n return $confirm.notify(\"success\", \"We've sent the invitationi again to '\" + $scope.member.email + \"'.\");\n };\n onError = function() {\n return $confirm.notify(\"error\", \"We haven't sent the invitation.\");\n };\n return $rs.memberships.resendInvitation($scope.member.id).then(onSuccess, onError);\n });\n $el.on(\"click\", \".delete\", function(event) {\n var message, title;\n event.preventDefault();\n title = \"Delete member\";\n message = member.user ? member.full_name : \"the invitation to \" + member.email;\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n finish();\n $ctrl.loadMembers();\n return $confirm.notify(\"success\", null, \"We've deleted \" + message + \".\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\", null, \"We have not been able to delete \" + message + \".\");\n };\n return $repo.remove(member).then(onSuccess, onError);\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowActions\", [\"$log\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", MembershipsRowActionsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/nav.coffee\n */\n\n(function() {\n var AdminNavigationDirective, module;\n\n AdminNavigationDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var section;\n section = $attrs.tgAdminNavigation;\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\"#adminmenu-\" + section + \" a\").addClass(\"active\");\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaAdmin\");\n\n module.directive(\"tgAdminNavigation\", AdminNavigationDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/project-profile.coffee\n */\n\n(function() {\n var ProjectDefaultValuesDirective, ProjectModulesDirective, ProjectProfileController, ProjectProfileDirective, bindOnce, debounce, groupBy, joinStr, mixOf, module, taiga, toString, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAdmin\");\n\n ProjectProfileController = (function(_super) {\n __extends(ProjectProfileController, _super);\n\n ProjectProfileController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function ProjectProfileController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Project profile - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:loaded\", (function(_this) {\n return function() {\n return _this.appTitle.set(\"Project profile - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n }\n\n ProjectProfileController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.scope.taskStatusList = _.sortBy(project.task_statuses, \"order\");\n _this.scope.prioritiesList = _.sortBy(project.priorities, \"order\");\n _this.scope.severitiesList = _.sortBy(project.severities, \"order\");\n _this.scope.issueTypesList = _.sortBy(project.issue_types, \"order\");\n _this.scope.issueStatusList = _.sortBy(project.issue_statuses, \"order\");\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ProjectProfileController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n ProjectProfileController.prototype.openDeleteLightbox = function() {\n return this.rootscope.$broadcast(\"deletelightbox:new\", this.scope.project);\n };\n\n return ProjectProfileController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"ProjectProfileController\", ProjectProfileController);\n\n ProjectProfileDirective = function($repo, $confirm, $loading, $navurls, $location) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.save($scope.project);\n promise.then(function() {\n var newUrl;\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n newUrl = $navurls.resolve(\"project-admin-project-profile-details\", {\n project: $scope.project.slug\n });\n $location.path(newUrl);\n return $scope.$emit(\"project:loaded\", $scope.project);\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectProfile\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgNavUrls\", \"$tgLocation\", ProjectProfileDirective]);\n\n ProjectDefaultValuesDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.save($scope.project);\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectDefaultValues\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", ProjectDefaultValuesDirective]);\n\n ProjectModulesDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit;\n form = $el.find(\"form\").checksley();\n submit = (function(_this) {\n return function() {\n var promise, target;\n if (!form.validate()) {\n return;\n }\n target = angular.element(\".admin-functionalities a.button-green\");\n $loading.start(target);\n promise = $repo.save($scope.project);\n promise.then(function() {\n $loading.finish(target);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:loaded\", $scope.project);\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n return $confirm.notify(\"error\", data._error_message);\n });\n };\n })(this);\n $el.on(\"submit\", \"form\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \".admin-functionalities a.button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n $scope.$watch(\"isVideoconferenceActivated\", function(isVideoconferenceActivated) {\n if (isVideoconferenceActivated) {\n return $el.find(\".videoconference-attributes\").removeClass(\"hidden\");\n } else {\n $el.find(\".videoconference-attributes\").addClass(\"hidden\");\n $scope.project.videoconferences = null;\n return $scope.project.videoconferences_salt = \"\";\n }\n });\n return $scope.$watch(\"project\", function(project) {\n if (project.videoconferences != null) {\n return $scope.isVideoconferenceActivated = true;\n } else {\n return $scope.isVideoconferenceActivated = false;\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectModules\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", ProjectModulesDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/project-profile.coffee\n */\n\n(function() {\n var ColorSelectionDirective, ProjectValuesController, ProjectValuesDirective, bindOnce, debounce, groupBy, joinStr, mixOf, module, taiga, toString, trim,\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAdmin\");\n\n ProjectValuesController = (function(_super) {\n __extends(ProjectValuesController, _super);\n\n ProjectValuesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function ProjectValuesController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.moveValue = __bind(this.moveValue, this);\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Project values - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"admin:project-values:move\", this.moveValue);\n }\n\n ProjectValuesController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ProjectValuesController.prototype.loadValues = function() {\n return this.rs[this.scope.resource].listValues(this.scope.projectId, this.scope.type).then((function(_this) {\n return function(values) {\n _this.scope.values = values;\n _this.scope.maxValueOrder = _.max(values, \"order\").order;\n return values;\n };\n })(this));\n };\n\n ProjectValuesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.q.all([_this.loadProject(), _this.loadValues()]);\n };\n })(this));\n };\n\n ProjectValuesController.prototype.moveValue = function(ctx, itemValue, itemIndex) {\n var r, values;\n values = this.scope.values;\n r = values.indexOf(itemValue);\n values.splice(r, 1);\n values.splice(itemIndex, 0, itemValue);\n _.each(values, function(value, index) {\n return value.order = index;\n });\n return this.repo.saveAll(values);\n };\n\n return ProjectValuesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"ProjectValuesController\", ProjectValuesController);\n\n ProjectValuesDirective = function($log, $repo, $confirm, $location, animationFrame) {\n var link, linkDragAndDrop, linkValue;\n linkDragAndDrop = function($scope, $el, $attrs) {\n var itemEl, newParentScope, oldParentScope, tdom;\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el.find(\".sortable\");\n tdom.sortable({\n handle: \".row.table-main.visualization\",\n dropOnEmpty: true,\n connectWith: \".project-values-body\",\n revert: 400,\n axis: \"y\"\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemValue;\n itemEl = ui.item;\n itemValue = itemEl.scope().value;\n itemIndex = itemEl.index();\n return $scope.$broadcast(\"admin:project-values:move\", itemValue, itemIndex);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n linkValue = function($scope, $el, $attrs) {\n var $ctrl, cancel, goToBottomList, initializeNewValue, saveValue, submit, valueType;\n $ctrl = $el.controller();\n valueType = $attrs.type;\n initializeNewValue = function() {\n return $scope.newValue = {\n \"name\": \"\",\n \"is_closed\": false,\n \"is_archived\": false\n };\n };\n initializeNewValue();\n goToBottomList = (function(_this) {\n return function(focus) {\n var table;\n if (focus == null) {\n focus = false;\n }\n table = $el.find(\".table-main\");\n $(document.body).scrollTop(table.offset().top + table.height());\n if (focus) {\n return $(\".new-value input\").focus();\n }\n };\n })(this);\n submit = debounce(2000, (function(_this) {\n return function() {\n var promise;\n promise = $repo.save($scope.project);\n promise.then(function() {\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n return $confirm.notify(\"error\", data._error_message);\n });\n };\n })(this));\n saveValue = debounce(2000, function(target) {\n var form, promise, value;\n form = target.parents(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n value = target.scope().value;\n promise = $repo.save(value);\n promise.then((function(_this) {\n return function() {\n var row;\n row = target.parents(\".row.table-main\");\n row.addClass(\"hidden\");\n return row.siblings(\".visualization\").removeClass('hidden');\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n });\n cancel = function(target) {\n var row, value;\n row = target.parents(\".row.table-main\");\n value = target.scope().value;\n return $scope.$apply(function() {\n row.addClass(\"hidden\");\n value.revert();\n return row.siblings(\".visualization\").removeClass('hidden');\n });\n };\n $el.on(\"submit\", \"form\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \"form a.button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \".show-add-new\", function(event) {\n event.preventDefault();\n $el.find(\".new-value\").removeClass('hidden');\n return goToBottomList(true);\n });\n $el.on(\"click\", \".add-new\", debounce(2000, function(event) {\n var form, promise;\n event.preventDefault();\n form = $el.find(\".new-value\").parents(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $scope.newValue.project = $scope.project.id;\n $scope.newValue.order = $scope.maxValueOrder ? $scope.maxValueOrder + 1 : 1;\n promise = $repo.create(valueType, $scope.newValue);\n promise.then((function(_this) {\n return function() {\n $ctrl.loadValues().then(function() {\n return animationFrame.add(function() {\n return goToBottomList();\n });\n });\n $el.find(\".new-value\").addClass(\"hidden\");\n return initializeNewValue();\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n }));\n $el.on(\"click\", \".delete-new\", function(event) {\n event.preventDefault();\n $el.find(\".new-value\").hide();\n return initializeNewValue();\n });\n $el.on(\"click\", \".edit-value\", function(event) {\n var editionRow, row, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n row = target.parents(\".row.table-main\");\n row.addClass(\"hidden\");\n editionRow = row.siblings(\".edition\");\n editionRow.removeClass('hidden');\n return editionRow.find('input:visible').first().focus().select();\n });\n $el.on(\"keyup\", \".edition input\", function(event) {\n var target;\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n return saveValue(target);\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n return cancel(target);\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return saveValue(target);\n });\n $el.on(\"click\", \".cancel\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return cancel(target);\n });\n return $el.on(\"click\", \".delete-value\", function(event) {\n var choices, replacement, subtitle, target, title, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.scope().value;\n choices = {};\n _.each($scope.values, function(option) {\n if (value.id !== option.id) {\n return choices[option.id] = option.name;\n }\n });\n title = \"Delete value\";\n subtitle = value.name;\n replacement = \"All items with this value will be changed to\";\n if (_.keys(choices).length === 0) {\n return $confirm.error(\"You can't delete all values.\");\n }\n return $confirm.askChoice(title, subtitle, choices, replacement).then(function(response) {\n var onError, onSucces;\n onSucces = function() {\n return $ctrl.loadValues()[\"finally\"](function() {\n return response.finish();\n });\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n return $repo.remove(value, {\n \"moveTo\": response.selected\n }).then(onSucces, onError);\n });\n });\n };\n link = function($scope, $el, $attrs) {\n linkDragAndDrop($scope, $el, $attrs);\n linkValue($scope, $el, $attrs);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectValues\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", \"animationFrame\", ProjectValuesDirective]);\n\n ColorSelectionDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var $ctrl;\n $ctrl = $el.controller();\n $scope.$watch($attrs.ngModel, function(element) {\n return $scope.color = element.color;\n });\n $el.on(\"click\", \".current-color\", function(event) {\n var body, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n $el.find(\".select-color\").hide();\n target.siblings(\".select-color\").show();\n body = angular.element(\"body\");\n return body.on(\"click\", (function(_this) {\n return function(event) {\n if (angular.element(event.target).parent(\".select-color\").length === 0) {\n $el.find(\".select-color\").hide();\n return body.unbind(\"click\");\n }\n };\n })(this));\n });\n $el.on(\"click\", \".select-color .color\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n $scope.$apply(function() {\n return $model.$modelValue.color = target.data(\"color\");\n });\n return $el.find(\".select-color\").hide();\n });\n $el.on(\"click\", \".select-color .selected-color\", function(event) {\n event.preventDefault();\n $scope.$apply(function() {\n return $model.$modelValue.color = $scope.color;\n });\n return $el.find(\".select-color\").hide();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgColorSelection\", ColorSelectionDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/memberships.coffee\n */\n\n(function() {\n var EditRoleDirective, NewRoleDirective, RolePermissionsDirective, RolesController, RolesDirective, bindMethods, bindOnce, debounce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaAdmin\");\n\n RolesController = (function(_super) {\n __extends(RolesController, _super);\n\n RolesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function RolesController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Permissions\";\n this.scope.project = {};\n this.scope.anyComputableRole = true;\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Roles - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n RolesController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.anyComputableRole = _.some(_.map(project.roles, function(point) {\n return point.computable;\n }));\n return project;\n };\n })(this));\n };\n\n RolesController.prototype.loadRoles = function() {\n return this.rs.roles.list(this.scope.projectId).then((function(_this) {\n return function(data) {\n _this.scope.roles = data;\n _this.scope.role = _this.scope.roles[0];\n return data;\n };\n })(this));\n };\n\n RolesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadRoles();\n };\n })(this));\n };\n\n RolesController.prototype.setRole = function(role) {\n this.scope.role = role;\n return this.scope.$broadcast(\"role:changed\", this.scope.role);\n };\n\n RolesController.prototype[\"delete\"] = function() {\n var choices, replacement, role, subtitle, title, warning, _i, _len, _ref;\n title = \"Delete Role\";\n subtitle = this.scope.role.name;\n replacement = \"All the users with this role will be moved to\";\n warning = \"Be careful, all role estimations will be removed\";\n choices = {};\n _ref = this.scope.roles;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n role = _ref[_i];\n if (role.id !== this.scope.role.id) {\n choices[role.id] = role.name;\n }\n }\n if (_.keys(choices).length === 0) {\n return this.confirm.error(\"You can't delete all values.\");\n }\n return this.confirm.askChoice(title, subtitle, choices, replacement, warning).then((function(_this) {\n return function(response) {\n var promise;\n promise = _this.repo.remove(_this.scope.role, {\n moveTo: response.selected\n });\n promise.then(function() {\n _this.loadProject();\n return _this.loadRoles()[\"finally\"](function() {\n return response.finish();\n });\n });\n return promise.then(null, function() {\n return _this.confirm.notify('error');\n });\n };\n })(this));\n };\n\n RolesController.prototype.setComputable = debounce(2000, function() {\n var onError, onSuccess;\n onSuccess = (function(_this) {\n return function() {\n _this.confirm.notify(\"success\");\n return _this.loadProject();\n };\n })(this);\n onError = (function(_this) {\n return function() {\n _this.confirm.notify(\"error\");\n return _this.scope.role.revert();\n };\n })(this);\n return this.repo.save(this.scope.role).then(onSuccess, onError);\n });\n\n return RolesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"RolesController\", RolesController);\n\n EditRoleDirective = function($repo, $confirm) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit, toggleView;\n toggleView = function() {\n $el.find('.total').toggle();\n return $el.find('.edit-role').toggle();\n };\n submit = function() {\n var promise;\n $scope.role.name = $el.find(\"input\").val();\n promise = $repo.save($scope.role);\n promise.then(function() {\n return $confirm.notify(\"success\");\n });\n promise.then(null, function(data) {\n return $confirm.notify(\"error\");\n });\n return toggleView();\n };\n $el.on(\"click\", \"a.icon-edit\", function() {\n toggleView();\n $el.find(\"input\").focus();\n return $el.find(\"input\").val($scope.role.name);\n });\n $el.on(\"click\", \"a.save\", submit);\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return submit();\n } else if (event.keyCode === 27) {\n return toggleView();\n }\n });\n $scope.$on(\"role:changed\", function() {\n if ($el.find('.edit-role').is(\":visible\")) {\n return toggleView();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgEditRole\", [\"$tgRepo\", \"$tgConfirm\", EditRoleDirective]);\n\n RolesDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRoles\", RolesDirective);\n\n NewRoleDirective = function($tgrepo, $confirm) {\n var DEFAULT_PERMISSIONS, link;\n DEFAULT_PERMISSIONS = [\"view_project\", \"view_milestones\", \"view_us\", \"view_tasks\", \"view_issues\"];\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $el.on(\"click\", \"a.add-button\", function(event) {\n event.preventDefault();\n $el.find(\".new\").removeClass(\"hidden\");\n $el.find(\".new\").focus();\n return $el.find(\".add-button\").hide();\n });\n return $el.on(\"keyup\", \".new\", function(event) {\n var newRole, onError, onSuccess, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newRole = {\n project: $scope.projectId,\n name: target.val(),\n permissions: DEFAULT_PERMISSIONS,\n order: _.max($scope.roles, function(r) {\n return r.order;\n }).order + 1,\n computable: false\n };\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new\").val('');\n onSuccess = function(role) {\n $scope.roles.push(role);\n $ctrl.setRole(role);\n $el.find(\".add-button\").show();\n return $ctrl.loadProject();\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n return $tgrepo.create(\"roles\", newRole).then(onSuccess, onError);\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new\").val('');\n return $el.find(\".add-button\").show();\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgNewRole\", [\"$tgRepo\", \"$tgConfirm\", NewRoleDirective]);\n\n RolePermissionsDirective = function($rootscope, $repo, $confirm) {\n var baseTemplate, categoryTemplate, link, resumeTemplate;\n resumeTemplate = _.template(\"
    <%- category.name %>
    \\n
    \\n
    <%- category.activePermissions %>/<%- category.permissions.length %>
    \\n <% _.each(category.permissions, function(permission) { %>\\n
    active<% } %>\\\"\\n title=\\\"<%- permission.description %>\\\">
    \\n <% }) %>\\n
    \\n
    \");\n categoryTemplate = _.template(\"
    \\\">\\n
    \\n
    \\n
    \\n
    \\n <% _.each(category.permissions, function(permission) { %>\\n
    \\\">\\n <%- permission.description %>\\n
    \\n checked=\\\"checked\\\"<% } %>/>\\n
    \\n Yes\\n No\\n
    \\n
    \\n <% }) %>\\n
    \\n
    \\n
    \");\n baseTemplate = _.template(\"
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, generateCategoriesFromRole, renderCategory, renderPermissions, renderResume;\n $ctrl = $el.controller();\n generateCategoriesFromRole = function(role) {\n var categories, issuePermissions, milestonePermissions, setActivePermissions, setActivePermissionsPerCategory, taskPermissions, userStoryPermissions, wikiPermissions;\n setActivePermissions = function(permissions) {\n return _.map(permissions, function(x) {\n var _ref;\n return _.extend({}, x, {\n active: (_ref = x[\"key\"], __indexOf.call(role.permissions, _ref) >= 0)\n });\n });\n };\n setActivePermissionsPerCategory = function(category) {\n return _.map(category, function(x) {\n return _.extend({}, x, {\n activePermissions: _.filter(x[\"permissions\"], \"active\").length\n });\n });\n };\n categories = [];\n milestonePermissions = [\n {\n key: \"view_milestones\",\n description: \"View sprints\"\n }, {\n key: \"add_milestone\",\n description: \"Add sprint\"\n }, {\n key: \"modify_milestone\",\n description: \"Modify sprint\"\n }, {\n key: \"delete_milestone\",\n description: \"Delete sprint\"\n }\n ];\n categories.push({\n name: \"Sprints\",\n permissions: setActivePermissions(milestonePermissions)\n });\n userStoryPermissions = [\n {\n key: \"view_us\",\n description: \"View user story\"\n }, {\n key: \"add_us\",\n description: \"Add user story\"\n }, {\n key: \"modify_us\",\n description: \"Modify user story\"\n }, {\n key: \"delete_us\",\n description: \"Delete user story\"\n }\n ];\n categories.push({\n name: \"User Stories\",\n permissions: setActivePermissions(userStoryPermissions)\n });\n taskPermissions = [\n {\n key: \"view_tasks\",\n description: \"View tasks\"\n }, {\n key: \"add_task\",\n description: \"Add task\"\n }, {\n key: \"modify_task\",\n description: \"Modify task\"\n }, {\n key: \"delete_task\",\n description: \"Delete task\"\n }\n ];\n categories.push({\n name: \"Tasks\",\n permissions: setActivePermissions(taskPermissions)\n });\n issuePermissions = [\n {\n key: \"view_issues\",\n description: \"View issues\"\n }, {\n key: \"add_issue\",\n description: \"Add issue\"\n }, {\n key: \"modify_issue\",\n description: \"Modify issue\"\n }, {\n key: \"delete_issue\",\n description: \"Delete issue\"\n }\n ];\n categories.push({\n name: \"Issues\",\n permissions: setActivePermissions(issuePermissions)\n });\n wikiPermissions = [\n {\n key: \"view_wiki_pages\",\n description: \"View wiki pages\"\n }, {\n key: \"add_wiki_page\",\n description: \"Add wiki page\"\n }, {\n key: \"modify_wiki_page\",\n description: \"Modify wiki page\"\n }, {\n key: \"delete_wiki_page\",\n description: \"Delete wiki page\"\n }, {\n key: \"view_wiki_links\",\n description: \"View wiki links\"\n }, {\n key: \"add_wiki_link\",\n description: \"Add wiki link\"\n }, {\n key: \"delete_wiki_link\",\n description: \"Delete wiki link\"\n }\n ];\n categories.push({\n name: \"Wiki\",\n permissions: setActivePermissions(wikiPermissions)\n });\n return setActivePermissionsPerCategory(categories);\n };\n renderResume = function(element, category) {\n return element.find(\".resume\").html(resumeTemplate({\n category: category\n }));\n };\n renderCategory = function(category, index) {\n var html;\n html = categoryTemplate({\n category: category,\n index: index\n });\n html = angular.element(html);\n renderResume(html, category);\n return html;\n };\n renderPermissions = function() {\n var html;\n $el.off();\n html = baseTemplate();\n _.each(generateCategoriesFromRole($scope.role), function(category, index) {\n return html = angular.element(html).append(renderCategory(category, index));\n });\n $el.html(html);\n $el.on(\"click\", \".resume\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return target.next().toggleClass(\"open\");\n });\n return $el.on(\"change\", \".category-item input\", function(event) {\n var getActivePermissions, onError, onSuccess, target;\n getActivePermissions = function() {\n var activePermissions;\n activePermissions = _.filter($el.find(\".category-item input\"), function(t) {\n return angular.element(t).is(\":checked\");\n });\n activePermissions = _.sortBy(_.map(activePermissions, function(t) {\n var permission;\n return permission = angular.element(t).parents(\".category-item\").data(\"id\");\n }));\n activePermissions.push(\"view_project\");\n return activePermissions;\n };\n target = angular.element(event.currentTarget);\n $scope.role.permissions = getActivePermissions();\n onSuccess = function(role) {\n var categories, categoryId;\n categories = generateCategoriesFromRole(role);\n categoryId = target.parents(\".category-config\").data(\"id\");\n renderResume(target.parents(\".category-config\"), categories[categoryId]);\n $rootscope.$broadcast(\"projects:reload\");\n $confirm.notify(\"success\");\n return $ctrl.loadProject();\n };\n onError = function() {\n $confirm.notify(\"error\");\n target.prop(\"checked\", !target.prop(\"checked\"));\n return $scope.role.permissions = getActivePermissions();\n };\n return $repo.save($scope.role).then(onSuccess, onError);\n });\n };\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $scope.$on(\"role:changed\", function() {\n return renderPermissions();\n });\n return bindOnce($scope, $attrs.ngModel, renderPermissions);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRolePermissions\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", RolePermissionsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/third-parties.coffee\n */\n\n(function() {\n var BitbucketController, BitbucketWebhooksDirective, GithubController, GithubWebhooksDirective, GitlabController, GitlabWebhooksDirective, SelectInputText, ValidOriginIpsDirective, bindMethods, debounce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindMethods = this.taiga.bindMethods;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAdmin\");\n\n GithubController = (function(_super) {\n __extends(GithubController, _super);\n\n GithubController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function GithubController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Github\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Github - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n GithubController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"github\").then((function(_this) {\n return function(github) {\n return _this.scope.github = github;\n };\n })(this));\n };\n\n GithubController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n GithubController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return GithubController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"GithubController\", GithubController);\n\n GitlabController = (function(_super) {\n __extends(GitlabController, _super);\n\n GitlabController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function GitlabController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Gitlab\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Gitlab - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:modules:reload\", (function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n }\n\n GitlabController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"gitlab\").then((function(_this) {\n return function(gitlab) {\n return _this.scope.gitlab = gitlab;\n };\n })(this));\n };\n\n GitlabController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n GitlabController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return GitlabController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"GitlabController\", GitlabController);\n\n BitbucketController = (function(_super) {\n __extends(BitbucketController, _super);\n\n BitbucketController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function BitbucketController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Bitbucket\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Bitbucket - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:modules:reload\", (function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n }\n\n BitbucketController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"bitbucket\").then((function(_this) {\n return function(bitbucket) {\n return _this.scope.bitbucket = bitbucket;\n };\n })(this));\n };\n\n BitbucketController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n BitbucketController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return BitbucketController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"BitbucketController\", BitbucketController);\n\n SelectInputText = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.on(\"click\", \".select-input-content\", function() {\n $el.find(\"input\").select();\n return $el.find(\".help-copy\").addClass(\"visible\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSelectInputText\", SelectInputText);\n\n GithubWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.github, \"github\");\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGithubWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", GithubWebhooksDirective]);\n\n GitlabWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.gitlab, \"gitlab\");\n promise.then(function() {\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:modules:reload\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGitlabWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", GitlabWebhooksDirective]);\n\n BitbucketWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.bitbucket, \"bitbucket\");\n promise.then(function() {\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:modules:reload\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBitbucketWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", BitbucketWebhooksDirective]);\n\n ValidOriginIpsDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $ngModel) {\n return $ngModel.$parsers.push(function(value) {\n value = $.trim(value);\n if (value === \"\") {\n return [];\n }\n return value.split(\",\");\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgValidOriginIps\", ValidOriginIpsDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var CreateProject, DeleteProjectDirective, bindOnce, debounce, module, taiga, timeout;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaProject\");\n\n CreateProject = function($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory) {\n var link;\n link = function($scope, $el, attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit, submitButton;\n $scope.data = {};\n $scope.templates = [];\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n onSuccessSubmit = function(response) {\n $cacheFactory.get('$http').removeAll();\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"projects:reload\");\n $confirm.notify(\"success\", \"Success\");\n $location.url($projectUrl.get(response));\n return lightboxService.close($el);\n };\n onErrorSubmit = function(response) {\n var error_field, error_step, selectors, _i, _len, _ref;\n $loading.finish(submitButton);\n form.setErrors(response);\n selectors = [];\n _ref = _.keys(response);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n error_field = _ref[_i];\n selectors.push(\"[name=\" + error_field + \"]\");\n }\n $el.find(\".active\").removeClass(\"active\");\n error_step = $el.find(selectors.join(\",\")).first().parents(\".wizard-step\");\n error_step.addClass(\"active\");\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(error_step.data(\"step\"));\n };\n submit = (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"projects\", $scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this);\n $scope.$on(\"projects:create\", function() {\n $scope.data = {\n total_story_points: 100,\n total_milestones: 5\n };\n if (!$scope.templates.length) {\n $rs.projects.templates().then((function(_this) {\n return function(result) {\n $scope.templates = result;\n return $scope.data.creation_template = _.head(_.filter($scope.templates, function(x) {\n return x.slug === \"scrum\";\n })).id;\n };\n })(this));\n } else {\n $scope.data.creation_template = _.head(_.filter($scope.templates, function(x) {\n return x.slug === \"scrum\";\n })).id;\n }\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\".create-step1\").addClass(\"active\");\n lightboxService.open($el);\n return timeout(600, function() {\n return $el.find(\".progress-bar\").addClass('step1');\n });\n });\n $el.on(\"click\", \".button-next\", function(event) {\n var current, field, next, step, valid, _i, _len, _ref;\n event.preventDefault();\n current = $el.find(\".active\");\n valid = true;\n _ref = form.fields;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n field = _ref[_i];\n if (current.find(\"[name=\" + (field.element.attr('name')) + \"]\").length) {\n valid = field.validate() !== false && valid;\n }\n }\n if (!valid) {\n return;\n }\n next = current.next();\n current.toggleClass('active');\n next.toggleClass('active');\n step = next.data('step');\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step);\n });\n $el.on(\"click\", \".button-prev\", function(event) {\n var current, prev, step;\n event.preventDefault();\n current = $el.find(\".active\");\n prev = current.prev();\n current.toggleClass('active');\n prev.toggleClass('active');\n step = prev.data('step');\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step);\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateProject\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$location\", \"$tgNavUrls\", \"$tgResources\", \"$projectUrl\", \"$tgLoading\", \"lightboxService\", \"$cacheFactory\", CreateProject]);\n\n DeleteProjectDirective = function($repo, $rootscope, $auth, $location, $navUrls, $confirm, lightboxService, tgLoader) {\n var link;\n link = function($scope, $el, $attrs) {\n var projectToDelete, submit;\n projectToDelete = null;\n $scope.$on(\"deletelightbox:new\", function(ctx, project) {\n lightboxService.open($el);\n return projectToDelete = project;\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = function() {\n var promise;\n tgLoader.start();\n lightboxService.close($el);\n promise = $repo.remove(projectToDelete);\n promise.then(function(data) {\n tgLoader.pageLoaded();\n $rootscope.$broadcast(\"projects:reload\");\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $confirm.notify(\"error\");\n return lightboxService.close($el);\n });\n };\n $el.on(\"click\", \".button-red\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n return $el.on(\"click\", \".button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbDeleteProject\", [\"$tgRepo\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfirm\", \"lightboxService\", \"tgLoader\", DeleteProjectDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var ProjectController, ProjectsController, ProjectsListDirective, ProjectsPaginationDirective, bindOnce, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaProject\");\n\n bindOnce = this.taiga.bindOnce;\n\n ProjectsController = (function(_super) {\n __extends(ProjectsController, _super);\n\n ProjectsController.$inject = [\"$scope\", \"$q\", \"$tgResources\", \"$rootScope\", \"$tgNavUrls\", \"$tgAuth\", \"$tgLocation\", \"$appTitle\", \"$projectUrl\", \"tgLoader\"];\n\n function ProjectsController(scope, q, rs, rootscope, navUrls, auth, location, appTitle, projectUrl, tgLoader) {\n var promise;\n this.scope = scope;\n this.q = q;\n this.rs = rs;\n this.rootscope = rootscope;\n this.navUrls = navUrls;\n this.auth = auth;\n this.location = location;\n this.appTitle = appTitle;\n this.projectUrl = projectUrl;\n this.appTitle.set(\"Projects\");\n if (!this.auth.isAuthenticated()) {\n this.location.path(this.navUrls.resolve(\"login\"));\n }\n this.user = this.auth.getUser();\n this.projects = [];\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.scope.$emit(\"projects:loaded\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n ProjectsController.prototype.loadInitialData = function() {\n return this.rs.projects.list().then((function(_this) {\n return function(projects) {\n var project, _i, _len;\n _this.projects = {\n 'recents': projects.slice(0, 8),\n 'all': projects\n };\n for (_i = 0, _len = projects.length; _i < _len; _i++) {\n project = projects[_i];\n project.url = _this.projectUrl.get(project);\n }\n return projects;\n };\n })(this));\n };\n\n ProjectsController.prototype.newProject = function() {\n return this.rootscope.$broadcast(\"projects:create\");\n };\n\n ProjectsController.prototype.logout = function() {\n this.auth.logout();\n return this.location.path(this.navUrls.resolve(\"login\"));\n };\n\n return ProjectsController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectsController\", ProjectsController);\n\n ProjectController = (function(_super) {\n __extends(ProjectController, _super);\n\n ProjectController.$inject = [\"$scope\", \"$tgResources\", \"$tgRepo\", \"$routeParams\", \"$q\", \"$rootScope\", \"$appTitle\", \"$tgLocation\", \"$tgNavUrls\"];\n\n function ProjectController(scope, rs, repo, params, q, rootscope, appTitle, location, navUrls) {\n var promise;\n this.scope = scope;\n this.rs = rs;\n this.repo = repo;\n this.params = params;\n this.q = q;\n this.rootscope = rootscope;\n this.appTitle = appTitle;\n this.location = location;\n this.navUrls = navUrls;\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.project.name);\n return _this.scope.$emit(\"regenerate:project-pagination\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n ProjectController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadPageData();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.scope.$emit(\"project:loaded\", _this.scope.project);\n };\n })(this));\n };\n\n ProjectController.prototype.loadPageData = function() {\n return this.q.all([this.loadProjectStats(), this.loadProject()]);\n };\n\n ProjectController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n return project;\n };\n })(this));\n };\n\n ProjectController.prototype.loadProjectStats = function() {\n return this.rs.projects.stats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n _this.scope.stats = stats;\n return stats;\n };\n })(this));\n };\n\n return ProjectController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectController\", ProjectController);\n\n ProjectsPaginationDirective = function($timeout) {\n var link;\n link = function($scope, $el, $attrs) {\n var checkButtonVisibility, container, containerSize, hasNextPage, hasPagination, hasPrevPage, hide, nextBtn, nextPage, pageSize, prevBtn, prevPage, remove, render, visible;\n prevBtn = $el.find(\".v-pagination-previous\");\n nextBtn = $el.find(\".v-pagination-next\");\n container = $el.find(\"ul\");\n pageSize = 0;\n containerSize = 0;\n render = function() {\n pageSize = $el.find(\".v-pagination-list\").height();\n if (container.find(\"li\").length) {\n if (hasPagination()) {\n if (hasNextPage()) {\n visible(nextBtn);\n } else {\n hide(nextBtn);\n }\n if (hasPrevPage()) {\n return visible(prevBtn);\n } else {\n return hide(prevBtn);\n }\n } else {\n return remove();\n }\n } else {\n return remove();\n }\n };\n hasPagination = function() {\n containerSize = container.height();\n return containerSize > pageSize;\n };\n hasPrevPage = function(top) {\n if (top == null) {\n top = -parseInt(container.css('top'), 10) || 0;\n }\n return top !== 0;\n };\n hasNextPage = function(top) {\n containerSize = container.height();\n if (!top) {\n top = -parseInt(container.css('top'), 10) || 0;\n }\n return containerSize > pageSize && top + pageSize < containerSize;\n };\n nextPage = function(callback) {\n var lastLi, maxTop, newTop, top;\n top = parseInt(container.css('top'), 10);\n newTop = top - pageSize;\n lastLi = $el.find(\".v-pagination-list li:last-child\");\n maxTop = -((lastLi.position().top + lastLi.outerHeight()) - pageSize);\n if (newTop < maxTop) {\n newTop = maxTop;\n }\n container.animate({\n \"top\": newTop\n }, callback);\n return newTop;\n };\n prevPage = function(callback) {\n var newTop, top;\n top = parseInt(container.css('top'), 10);\n newTop = top + pageSize;\n if (newTop > 0) {\n newTop = 0;\n }\n container.animate({\n \"top\": newTop\n }, callback);\n return newTop;\n };\n visible = function(element) {\n return element.css('visibility', 'visible');\n };\n hide = function(element) {\n return element.css('visibility', 'hidden');\n };\n checkButtonVisibility = function() {};\n remove = function() {\n container.css('top', 0);\n hide(prevBtn);\n return hide(nextBtn);\n };\n $el.on(\"click\", \".v-pagination-previous\", function(event) {\n var newTop;\n event.preventDefault();\n if (container.is(':animated')) {\n return;\n }\n visible(nextBtn);\n newTop = prevPage();\n if (!hasPrevPage(newTop)) {\n return hide(prevBtn);\n }\n });\n $el.on(\"click\", \".v-pagination-next\", function(event) {\n var newTop;\n event.preventDefault();\n if (container.is(':animated')) {\n return;\n }\n visible(prevBtn);\n newTop = -nextPage();\n if (!hasNextPage(newTop)) {\n return hide(nextBtn);\n }\n });\n $scope.$on(\"regenerate:project-pagination\", function() {\n remove();\n return render();\n });\n $(window).on(\"resize.projects-pagination\", render);\n return $scope.$on(\"$destroy\", function() {\n return $(window).off(\"resize.projects-pagination\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectsPagination\", ['$timeout', ProjectsPaginationDirective]);\n\n ProjectsListDirective = function($compile) {\n var link, template;\n template = _.template(\"
    \\n
    \\n \\n
    \\n \\n
    \\n \\n
    \\n
    \");\n link = function($scope, $el, $attrs, $ctrls) {\n var render;\n render = function(projects) {\n $el.html($compile(template({\n projects: projects\n }))($scope));\n return $scope.$emit(\"regenerate:project-pagination\");\n };\n return $scope.$watch(\"projects\", function(projects) {\n if (projects != null) {\n return render(projects);\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectsList\", [\"$compile\", ProjectsListDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/bind.coffee\n */\n\n(function() {\n var BindHtmlDirective, BindOnceAltDirective, BindOnceBindDirective, BindOnceHrefDirective, BindOnceHtmlDirective, BindOnceRefDirective, BindOnceSrcDirective, BindOnceTitleDirective, BindTitleDirective, bindOnce, module;\n\n bindOnce = this.taiga.bindOnce;\n\n BindOnceBindDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoBind, function(val) {\n return $el.text(val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceHtmlDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoHtml, function(val) {\n return $el.html(val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceRefDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoRef, function(val) {\n return $el.html(\"#\" + val + \" \");\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceSrcDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoSrc, function(val) {\n return $el.attr(\"src\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceHrefDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoHref, function(val) {\n return $el.attr(\"href\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceAltDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoAlt, function(val) {\n return $el.attr(\"alt\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceTitleDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoTitle, function(val) {\n return $el.attr(\"title\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindTitleDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$watch($attrs.tgTitleHtml, function(val) {\n if (val != null) {\n return $el.attr(\"title\", val);\n }\n });\n };\n return {\n link: link\n };\n };\n\n BindHtmlDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$watch($attrs.tgBindHtml, function(val) {\n if (val != null) {\n return $el.html(val);\n }\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaBase\");\n\n module.directive(\"tgBoBind\", BindOnceBindDirective);\n\n module.directive(\"tgBoHtml\", BindOnceHtmlDirective);\n\n module.directive(\"tgBoRef\", BindOnceRefDirective);\n\n module.directive(\"tgBoSrc\", BindOnceSrcDirective);\n\n module.directive(\"tgBoHref\", BindOnceHrefDirective);\n\n module.directive(\"tgBoAlt\", BindOnceAltDirective);\n\n module.directive(\"tgBoTitle\", BindOnceTitleDirective);\n\n module.directive(\"tgBindTitle\", BindTitleDirective);\n\n module.directive(\"tgBindHtml\", BindHtmlDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/conf.coffee\n */\n\n(function() {\n var ConfigurationService, module;\n\n ConfigurationService = (function() {\n function ConfigurationService() {\n this.config = window.taigaConfig;\n }\n\n ConfigurationService.prototype.get = function(key, defaultValue) {\n if (defaultValue == null) {\n defaultValue = null;\n }\n if (_.has(this.config, key)) {\n return this.config[key];\n }\n return defaultValue;\n };\n\n return ConfigurationService;\n\n })();\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgConfig\", ConfigurationService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/contrib.coffee\n */\n\n(function() {\n var ContribController, module, taigaContribPlugins,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taigaContribPlugins = this.taigaContribPlugins = this.taigaContribPlugins || [];\n\n ContribController = (function(_super) {\n __extends(ContribController, _super);\n\n ContribController.$inject = [\"$rootScope\", \"$scope\", \"$routeParams\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$appTitle\"];\n\n function ContribController(rootScope, scope, params, repo, rs, confirm, appTitle) {\n var promise;\n this.rootScope = rootScope;\n this.scope = scope;\n this.params = params;\n this.repo = repo;\n this.rs = rs;\n this.confirm = confirm;\n this.appTitle = appTitle;\n this.scope.currentPlugin = _.first(_.where(taigaContribPlugins, {\n \"slug\": this.params.plugin\n }));\n this.scope.pluginTemplate = \"contrib/\" + this.scope.currentPlugin.slug;\n this.scope.projectSlug = this.params.pslug;\n this.scope.adminPlugins = _.where(this.rootScope.contribPlugins, {\n \"type\": \"admin\"\n });\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(_this.scope.project.name);\n };\n })(this));\n promise.then(null, (function(_this) {\n return function() {\n return _this.confirm.notify(\"error\");\n };\n })(this));\n }\n\n ContribController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.$broadcast('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ContribController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n return ContribController;\n\n })(taiga.Controller);\n\n module = angular.module(\"taigaBase\");\n\n module.controller(\"ContribController\", ContribController);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/filters.coffee\n */\n\n(function() {\n var FiltersStorageService, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n FiltersStorageService = (function(_super) {\n __extends(FiltersStorageService, _super);\n\n FiltersStorageService.$inject = [\"$tgStorage\", \"$routeParams\"];\n\n function FiltersStorageService(storage, params) {\n this.storage = storage;\n this.params = params;\n }\n\n FiltersStorageService.prototype.generateHash = function(components) {\n if (components == null) {\n components = [];\n }\n components = _.map(components, function(x) {\n return JSON.stringify(x);\n });\n return hex_sha1(components.join(\":\"));\n };\n\n return FiltersStorageService;\n\n })(taiga.Service);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/http.coffee\n */\n\n(function() {\n var HttpService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n HttpService = (function(_super) {\n __extends(HttpService, _super);\n\n HttpService.$inject = [\"$http\", \"$q\", \"$tgStorage\"];\n\n HttpService.prototype.headers = function() {\n var token;\n token = this.storage.get('token');\n if (token) {\n return {\n \"Authorization\": \"Bearer \" + token\n };\n }\n return {};\n };\n\n function HttpService(http, q, storage) {\n this.http = http;\n this.q = q;\n this.storage = storage;\n HttpService.__super__.constructor.call(this);\n }\n\n HttpService.prototype.request = function(options) {\n options.headers = _.merge({}, options.headers || {}, this.headers());\n if (_.isPlainObject(options.data)) {\n options.data = JSON.stringify(options.data);\n }\n return this.http(options);\n };\n\n HttpService.prototype.get = function(url, params, options) {\n options = _.merge({\n method: \"GET\",\n url: url\n }, options);\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.post = function(url, data, params, options) {\n options = _.merge({\n method: \"POST\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.put = function(url, data, params, options) {\n options = _.merge({\n method: \"PUT\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.patch = function(url, data, params, options) {\n options = _.merge({\n method: \"PATCH\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype[\"delete\"] = function(url, data, params, options) {\n options = _.merge({\n method: \"DELETE\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n return HttpService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgHttp\", HttpService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/i18n.coffee\n */\n\n(function() {\n var I18nDirective, I18nService, bindOnce, defaults, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n defaults = {\n ns: \"app\",\n fallbackLng: \"en\",\n async: false,\n lng: \"en\"\n };\n\n I18nService = (function(_super) {\n __extends(I18nService, _super);\n\n function I18nService(rootscope, localesEn) {\n this.rootscope = rootscope;\n this.options = _.clone(defaults, true);\n this.options.resStore = {\n en: {\n app: localesEn\n }\n };\n }\n\n I18nService.prototype.setLanguage = function(language) {\n i18n.setLng(language);\n this.rootscope.currentLang = language;\n return this.rootscope.$broadcast(\"i18n:changeLang\", language);\n };\n\n I18nService.prototype.initialize = function() {\n i18n.init(this.options);\n return this.rootscope.t = i18n.t;\n };\n\n I18nService.prototype.t = function(path, opts) {\n return i18n.t(path, opts);\n };\n\n return I18nService;\n\n })(taiga.Service);\n\n I18nDirective = function($rootscope, $i18n) {\n var link;\n link = function($scope, $el, $attrs) {\n var ns, options, opts, v, values, _i, _len, _ref, _results;\n values = $attrs.tr.split(\",\");\n options = $attrs.trOpts || '{}';\n opts = $scope.$eval(options);\n _results = [];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n v = values[_i];\n if (v.indexOf(\":\") === -1) {\n _results.push($el.html(_.escape($i18n.t(v, opts))));\n } else {\n _ref = v.split(\":\"), ns = _ref[0], v = _ref[1];\n _results.push($el.attr(ns, _.escape($i18n.t(v, opts))));\n }\n }\n return _results;\n };\n return {\n link: link,\n restrict: \"A\",\n scope: false\n };\n };\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgI18n\", [\"$rootScope\", \"localesEn\", I18nService]);\n\n module.directive(\"tr\", [\"$rootScope\", \"$tgI18n\", I18nDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/location.coffee\n */\n\n(function() {\n var locationFactory, module;\n\n locationFactory = function($location, $route, $rootscope) {\n $location.noreload = function(scope) {\n var lastRoute, un;\n lastRoute = $route.current;\n un = scope.$on(\"$locationChangeSuccess\", function() {\n $route.current = lastRoute;\n return un();\n });\n return $location;\n };\n return $location;\n };\n\n module = angular.module(\"taigaBase\");\n\n module.factory(\"$tgLocation\", [\"$location\", \"$route\", \"$rootScope\", locationFactory]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/model.coffee\n */\n\n(function() {\n var Model, ModelService, module, provider, taiga,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n Model = (function() {\n function Model(name, data, dataTypes) {\n this._attrs = data;\n this._name = name;\n this._dataTypes = dataTypes;\n this.setAttrs(data);\n this.initialize();\n }\n\n Model.prototype.clone = function() {\n var instance;\n instance = new Model(this._name, this._attrs, this._dataTypes);\n instance._modifiedAttrs = this._modifiedAttrs;\n instance._isModified = this._isModified;\n return instance;\n };\n\n Model.prototype.applyCasts = function() {\n var attrName, castMethod, castName, _ref, _results;\n _ref = this._dataTypes;\n _results = [];\n for (attrName in _ref) {\n castName = _ref[attrName];\n castMethod = service.casts[castName];\n if (!castMethod) {\n continue;\n }\n _results.push(this._attrs[attrName] = castMethod(this._attrs[attrName]));\n }\n return _results;\n };\n\n Model.prototype.getIdAttrName = function() {\n return \"id\";\n };\n\n Model.prototype.getName = function() {\n return this._name;\n };\n\n Model.prototype.getAttrs = function(patch) {\n if (patch == null) {\n patch = false;\n }\n if (this._attrs.version != null) {\n this._modifiedAttrs.version = this._attrs.version;\n }\n if (patch) {\n return _.extend({}, this._modifiedAttrs);\n }\n return _.extend({}, this._attrs, this._modifiedAttrs);\n };\n\n Model.prototype.setAttrs = function(attrs) {\n this._attrs = attrs;\n this._modifiedAttrs = {};\n this.applyCasts();\n return this._isModified = false;\n };\n\n Model.prototype.setAttr = function(name, value) {\n this._modifiedAttrs[name] = value;\n return this._isModified = true;\n };\n\n Model.prototype.initialize = function() {\n var getter, self, setter;\n self = this;\n getter = function(name) {\n return function() {\n if (typeof name === 'string' && name.substr(0, 2) === \"__\") {\n return self[name];\n }\n if (__indexOf.call(_.keys(self._modifiedAttrs), name) < 0) {\n return self._attrs[name];\n }\n return self._modifiedAttrs[name];\n };\n };\n setter = function(name) {\n return function(value) {\n if (typeof name === 'string' && name.substr(0, 2) === \"__\") {\n self[name] = value;\n return;\n }\n if (self._attrs[name] !== value) {\n self._modifiedAttrs[name] = value;\n self._isModified = true;\n } else {\n delete self._modifiedAttrs[name];\n }\n };\n };\n return _.each(this._attrs, function(value, name) {\n var options;\n options = {\n get: getter(name),\n set: setter(name),\n enumerable: true,\n configurable: true\n };\n return Object.defineProperty(self, name, options);\n });\n };\n\n Model.prototype.serialize = function() {\n var data;\n data = {\n \"data\": _.clone(this._attrs),\n \"name\": this._name\n };\n return JSON.stringify(data);\n };\n\n Model.prototype.isModified = function() {\n return this._isModified;\n };\n\n Model.prototype.isAttributeModified = function(attribute) {\n return this._modifiedAttrs[attribute] != null;\n };\n\n Model.prototype.markSaved = function() {\n this._isModified = false;\n this._attrs = this.getAttrs();\n return this._modifiedAttrs = {};\n };\n\n Model.prototype.revert = function() {\n this._modifiedAttrs = {};\n return this._isModified = false;\n };\n\n Model.desSerialize = function(sdata) {\n var ddata, model;\n ddata = JSON.parse(sdata);\n model = new Model(ddata.url, ddata.data);\n return model;\n };\n\n return Model;\n\n })();\n\n taiga = this.taiga;\n\n ModelService = (function(_super) {\n __extends(ModelService, _super);\n\n ModelService.$inject = [\"$q\", \"$tgUrls\", \"$tgStorage\", \"$tgHttp\"];\n\n function ModelService(q, urls, storage, http) {\n this.q = q;\n this.urls = urls;\n this.storage = storage;\n this.http = http;\n ModelService.__super__.constructor.call(this);\n }\n\n return ModelService;\n\n })(taiga.Service);\n\n provider = function($q, $http, $gmUrls, $gmStorage) {\n var service;\n service = {};\n service.make_model = function(name, data, cls, dataTypes) {\n if (cls == null) {\n cls = Model;\n }\n if (dataTypes == null) {\n dataTypes = {};\n }\n return new cls(name, data, dataTypes);\n };\n service.cls = Model;\n service.casts = {\n int: function(value) {\n return parseInt(value, 10);\n },\n float: function(value) {\n return parseFloat(value, 10);\n }\n };\n return service;\n };\n\n module = angular.module(\"taigaBase\");\n\n module.factory(\"$tgModel\", [\"$q\", \"$http\", \"$tgUrls\", \"$tgStorage\", provider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/navurl.coffee\n */\n\n(function() {\n var NavigationUrlsDirective, NavigationUrlsService, bindOnce, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaBase\");\n\n NavigationUrlsService = (function(_super) {\n __extends(NavigationUrlsService, _super);\n\n function NavigationUrlsService() {\n this.urls = {};\n }\n\n NavigationUrlsService.prototype.update = function(urls) {\n return this.urls = _.merge({}, this.urls, urls || {});\n };\n\n NavigationUrlsService.prototype.formatUrl = function(url, ctx) {\n var replacer;\n if (ctx == null) {\n ctx = {};\n }\n replacer = function(match) {\n match = trim(match, \":\");\n return ctx[match] || \"undefined\";\n };\n return url.replace(/(:\\w+)/g, replacer);\n };\n\n NavigationUrlsService.prototype.resolve = function(name, ctx) {\n var url;\n url = this.urls[name];\n if (!url) {\n return \"\";\n }\n if (ctx) {\n return this.formatUrl(url, ctx);\n }\n return url;\n };\n\n return NavigationUrlsService;\n\n })(taiga.Service);\n\n module.service(\"$tgNavUrls\", NavigationUrlsService);\n\n NavigationUrlsDirective = function($navurls, $auth, $q, $location) {\n var bindOnceP, link, parseNav;\n bindOnceP = function($scope, attr) {\n var defered;\n defered = $q.defer();\n bindOnce($scope, attr, function(v) {\n return defered.resolve(v);\n });\n return defered.promise;\n };\n parseNav = function(data, $scope) {\n var name, params, promises, values, _ref;\n _ref = _.map(data.split(\":\"), trim), name = _ref[0], params = _ref[1];\n if (params) {\n params = _.map(params.split(\",\"), trim);\n } else {\n params = [];\n }\n values = _.map(params, function(x) {\n return trim(x.split(\"=\")[1]);\n });\n promises = _.map(values, function(x) {\n return bindOnceP($scope, x);\n });\n return $q.all(promises).then(function() {\n var item, key, options, value, _i, _len, _ref1;\n options = {};\n for (_i = 0, _len = params.length; _i < _len; _i++) {\n item = params[_i];\n _ref1 = _.map(item.split(\"=\"), trim), key = _ref1[0], value = _ref1[1];\n options[key] = $scope.$eval(value);\n }\n return [name, options];\n });\n };\n link = function($scope, $el, $attrs) {\n if ($el.is(\"a\")) {\n $el.attr(\"href\", \"#\");\n }\n $el.on(\"mouseenter\", function(event) {\n var target;\n target = $(event.currentTarget);\n if (!target.data(\"fullUrl\")) {\n return parseNav($attrs.tgNav, $scope).then(function(result) {\n var fullUrl, name, options, url, user;\n name = result[0], options = result[1];\n user = $auth.getUser();\n if (user) {\n options.user = user.username;\n }\n url = $navurls.resolve(name);\n fullUrl = $navurls.formatUrl(url, options);\n target.data(\"fullUrl\", fullUrl);\n if (target.is(\"a\")) {\n target.attr(\"href\", fullUrl);\n }\n return $el.on(\"click\", function(event) {\n event.preventDefault();\n target = $(event.currentTarget);\n if (target.hasClass('noclick')) {\n return;\n }\n fullUrl = target.data(\"fullUrl\");\n switch (event.which) {\n case 1:\n $location.url(fullUrl);\n return $scope.$apply();\n case 2:\n return window.open(fullUrl);\n }\n });\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgNav\", [\"$tgNavUrls\", \"$tgAuth\", \"$q\", \"$tgLocation\", NavigationUrlsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/repository.coffee\n */\n\n(function() {\n var RepositoryService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n RepositoryService = (function(_super) {\n __extends(RepositoryService, _super);\n\n RepositoryService.$inject = [\"$q\", \"$tgModel\", \"$tgStorage\", \"$tgHttp\", \"$tgUrls\"];\n\n function RepositoryService(q, model, storage, http, urls) {\n this.q = q;\n this.model = model;\n this.storage = storage;\n this.http = http;\n this.urls = urls;\n RepositoryService.__super__.constructor.call(this);\n }\n\n RepositoryService.prototype.resolveUrlForModel = function(model) {\n var idAttrName;\n idAttrName = model.getIdAttrName();\n return \"\" + (this.urls.resolve(model.getName())) + \"/\" + model[idAttrName];\n };\n\n RepositoryService.prototype.resolveUrlForAttributeModel = function(model) {\n return this.urls.resolve(model.getName(), model.parent);\n };\n\n RepositoryService.prototype.create = function(name, data, dataTypes, extraParams) {\n var defered, promise, url;\n if (dataTypes == null) {\n dataTypes = {};\n }\n if (extraParams == null) {\n extraParams = {};\n }\n defered = this.q.defer();\n url = this.urls.resolve(name);\n promise = this.http.post(url, JSON.stringify(data));\n promise.success((function(_this) {\n return function(_data, _status) {\n return defered.resolve(_this.model.make_model(name, _data, null, dataTypes));\n };\n })(this));\n promise.error((function(_this) {\n return function(data, status) {\n return defered.reject(data);\n };\n })(this));\n return defered.promise;\n };\n\n RepositoryService.prototype.remove = function(model, params) {\n var defered, promise, url;\n if (params == null) {\n params = {};\n }\n defered = this.q.defer();\n url = this.resolveUrlForModel(model);\n promise = this.http[\"delete\"](url, {}, params);\n promise.success(function(data, status) {\n return defered.resolve(model);\n });\n promise.error(function(data, status) {\n return defered.reject(model);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.saveAll = function(models, patch) {\n var promises;\n if (patch == null) {\n patch = true;\n }\n promises = _.map(models, (function(_this) {\n return function(x) {\n return _this.save(x, true);\n };\n })(this));\n return this.q.all(promises);\n };\n\n RepositoryService.prototype.save = function(model, patch) {\n var data, defered, promise, url;\n if (patch == null) {\n patch = true;\n }\n defered = this.q.defer();\n if (!model.isModified() && patch) {\n defered.resolve(model);\n return defered.promise;\n }\n url = this.resolveUrlForModel(model);\n data = JSON.stringify(model.getAttrs(patch));\n if (patch) {\n promise = this.http.patch(url, data);\n } else {\n promise = this.http.put(url, data);\n }\n promise.success((function(_this) {\n return function(data, status) {\n model._isModified = false;\n model._attrs = _.extend(model.getAttrs(), data);\n model._modifiedAttrs = {};\n model.applyCasts();\n return defered.resolve(model);\n };\n })(this));\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.saveAttribute = function(model, attribute, patch) {\n var data, defered, promise, url;\n if (patch == null) {\n patch = true;\n }\n defered = this.q.defer();\n if (!model.isModified() && patch) {\n defered.resolve(model);\n return defered.promise;\n }\n url = this.resolveUrlForAttributeModel(model);\n data = {};\n data[attribute] = model.getAttrs();\n if (patch) {\n promise = this.http.patch(url, data);\n } else {\n promise = this.http.put(url, data);\n }\n promise.success((function(_this) {\n return function(data, status) {\n model._isModified = false;\n model._attrs = _.extend(model.getAttrs(), data);\n model._modifiedAttrs = {};\n model.applyCasts();\n return defered.resolve(model);\n };\n })(this));\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.refresh = function(model) {\n var defered, promise, url;\n defered = this.q.defer();\n url = this.resolveUrlForModel(model);\n promise = this.http.get(url);\n promise.success(function(data, status) {\n model._modifiedAttrs = {};\n model._attrs = data;\n model._isModified = false;\n model.applyCasts();\n return defered.resolve(model);\n });\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.queryMany = function(name, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return _.map(data.data, function(x) {\n return _this.model.make_model(name, x);\n });\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOneAttribute = function(name, id, attribute, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name, id);\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n var model;\n model = _this.model.make_model(name, data.data[attribute]);\n model.parent = id;\n return model;\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOne = function(name, id, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n if (id) {\n url = \"\" + url + \"/\" + id;\n }\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return _this.model.make_model(name, data.data);\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOneRaw = function(name, id, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n if (id) {\n url = \"\" + url + \"/\" + id;\n }\n httpOptions = _.merge({\n headers: {}\n }, options);\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n\n RepositoryService.prototype.queryPaginated = function(name, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n httpOptions = _.merge({\n headers: {}\n }, options);\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n var headers, result;\n headers = data.headers();\n result = {};\n result.models = _.map(data.data, function(x) {\n return _this.model.make_model(name, x);\n });\n result.count = parseInt(headers[\"x-pagination-count\"], 10);\n result.current = parseInt(headers[\"x-pagination-current\"] || 1, 10);\n result.paginatedBy = parseInt(headers[\"x-paginated-by\"], 10);\n return result;\n };\n })(this));\n };\n\n RepositoryService.prototype.resolve = function(options) {\n var cache, params;\n params = {};\n if (options.pslug != null) {\n params.project = options.pslug;\n }\n if (options.usref != null) {\n params.us = options.usref;\n }\n if (options.taskref != null) {\n params.task = options.taskref;\n }\n if (options.issueref != null) {\n params.issue = options.issueref;\n }\n if (options.sslug != null) {\n params.milestone = options.sslug;\n }\n if (options.wikipage != null) {\n params.wikipage = options.wikipage;\n }\n cache = !(options.wikipage || options.sslug);\n return this.queryOneRaw(\"resolver\", null, params, {\n cache: cache\n });\n };\n\n return RepositoryService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgRepo\", RepositoryService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/storage.coffee\n */\n\n(function() {\n var StorageService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n StorageService = (function(_super) {\n __extends(StorageService, _super);\n\n StorageService.$inject = [\"$rootScope\"];\n\n function StorageService($rootScope) {\n StorageService.__super__.constructor.call(this);\n }\n\n StorageService.prototype.get = function(key, _default) {\n var serializedValue;\n serializedValue = localStorage.getItem(key);\n if (serializedValue === null) {\n return _default || null;\n }\n return JSON.parse(serializedValue);\n };\n\n StorageService.prototype.set = function(key, val) {\n if (_.isObject(key)) {\n return _.each(key, (function(_this) {\n return function(val, key) {\n return _this.set(key, val);\n };\n })(this));\n } else {\n return localStorage.setItem(key, JSON.stringify(val));\n }\n };\n\n StorageService.prototype.contains = function(key) {\n var value;\n value = this.get(key);\n return value !== null;\n };\n\n StorageService.prototype.remove = function(key) {\n return localStorage.removeItem(key);\n };\n\n StorageService.prototype.clear = function() {\n return localStorage.clear();\n };\n\n return StorageService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgStorage\", StorageService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/http.coffee\n */\n\n(function() {\n var UrlsService, format, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n format = function(fmt, obj) {\n obj = _.clone(obj);\n return fmt.replace(/%s/g, function(match) {\n return String(obj.shift());\n });\n };\n\n taiga = this.taiga;\n\n UrlsService = (function(_super) {\n __extends(UrlsService, _super);\n\n UrlsService.$inject = [\"$tgConfig\"];\n\n function UrlsService(config) {\n this.config = config;\n this.urls = {};\n this.mainUrl = config.get(\"api\");\n }\n\n UrlsService.prototype.update = function(urls) {\n return this.urls = _.merge(this.urls, urls);\n };\n\n UrlsService.prototype.resolve = function() {\n var args, name, url;\n args = _.toArray(arguments);\n if (args.length === 0) {\n throw Error(\"wrong arguments to setUrls\");\n }\n name = args.slice(0, 1)[0];\n url = format(this.urls[name], args.slice(1));\n return format(\"%s/%s\", [_.str.rtrim(this.mainUrl, \"/\"), _.str.ltrim(url, \"/\")]);\n };\n\n return UrlsService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service('$tgUrls', UrlsService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/attachments.coffee\n */\n\n(function() {\n var module, resourceProvider, sizeFormat, taiga;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n resourceProvider = function($rootScope, $config, $urls, $model, $repo, $auth, $q) {\n var service;\n service = {};\n service.list = function(urlName, objectId, projectId) {\n var params;\n params = {\n object_id: objectId,\n project: projectId\n };\n return $repo.queryMany(urlName, params);\n };\n service.create = function(urlName, projectId, objectId, file) {\n var data, defered, maxFileSize, response, uploadComplete, uploadFailed, uploadProgress, xhr;\n defered = $q.defer();\n if (file === void 0) {\n defered.reject(null);\n return defered.promise;\n }\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize && file.size > maxFileSize) {\n response = {\n status: 413,\n data: {\n _error_message: \"'\" + file.name + \"' (\" + (sizeFormat(file.size)) + \") is too heavy for our oompa loompas, try it with a smaller than (\" + (sizeFormat(maxFileSize)) + \")\"\n }\n };\n defered.reject(response);\n return defered.promise;\n }\n uploadProgress = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n file.status = \"in-progress\";\n file.size = sizeFormat(evt.total);\n file.progressMessage = \"upload \" + (sizeFormat(evt.loaded)) + \" of \" + (sizeFormat(evt.total));\n return file.progressPercent = \"\" + (Math.round((evt.loaded / evt.total) * 100)) + \"%\";\n });\n };\n })(this);\n uploadComplete = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n var data, model;\n file.status = \"done\";\n try {\n data = JSON.parse(evt.target.responseText);\n } catch (_error) {\n data = {};\n }\n model = $model.make_model(urlName, data);\n return defered.resolve(model);\n });\n };\n })(this);\n uploadFailed = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n file.status = \"error\";\n return defered.reject(\"fail\");\n });\n };\n })(this);\n data = new FormData();\n data.append(\"project\", projectId);\n data.append(\"object_id\", objectId);\n data.append(\"attached_file\", file);\n xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", uploadProgress, false);\n xhr.addEventListener(\"load\", uploadComplete, false);\n xhr.addEventListener(\"error\", uploadFailed, false);\n xhr.open(\"POST\", $urls.resolve(urlName));\n xhr.setRequestHeader(\"Authorization\", \"Bearer \" + ($auth.getToken()));\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send(data);\n return defered.promise;\n };\n return function(instance) {\n return instance.attachments = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgAttachmentsResourcesProvider\", [\"$rootScope\", \"$tgConfig\", \"$tgUrls\", \"$tgModel\", \"$tgRepo\", \"$tgAuth\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/history.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(type, objectId) {\n return $repo.queryOneRaw(\"history/\" + type, objectId);\n };\n service.deleteComment = function(type, objectId, activityId) {\n var params, url;\n url = $urls.resolve(\"history/\" + type);\n url = \"\" + url + \"/\" + objectId + \"/delete_comment\";\n params = {\n id: activityId\n };\n return $http.post(url, null, params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n service.undeleteComment = function(type, objectId, activityId) {\n var params, url;\n url = $urls.resolve(\"history/\" + type);\n url = \"\" + url + \"/\" + objectId + \"/undelete_comment\";\n params = {\n id: activityId\n };\n return $http.post(url, null, params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n return function(instance) {\n return instance.history = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgHistoryResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/projects.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo) {\n var service;\n service = {};\n service.get = function(token) {\n return $repo.queryOne(\"invitations\", token);\n };\n return function(instance) {\n return instance.invitations = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgInvitationsResourcesProvider\", [\"$tgRepo\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/issues.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage, $q) {\n var filtersHashSuffix, hashSuffix, myFiltersHashSuffix, service;\n service = {};\n hashSuffix = \"issues-queryparams\";\n filtersHashSuffix = \"issues-filters\";\n myFiltersHashSuffix = \"issues-my-filters\";\n service.get = function(projectId, issueId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"issues\", issueId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"issues\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.list = function(projectId, filters, options) {\n var params;\n params = {\n project: projectId\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryPaginated(\"issues\", params, options);\n };\n service.bulkCreate = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-create-issues\");\n params = {\n project_id: projectId,\n bulk_issues: data\n };\n return $http.post(url, params);\n };\n service.stats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/issues_stats\");\n };\n service.filtersData = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/issue_filters_data\");\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeFilters = function(projectSlug, params) {\n var hash, ns;\n ns = \"\" + projectSlug + \":\" + filtersHashSuffix;\n hash = generateHash([projectSlug, ns]);\n return $storage.set(hash, params);\n };\n service.getFilters = function(projectSlug) {\n var hash, ns;\n ns = \"\" + projectSlug + \":\" + filtersHashSuffix;\n hash = generateHash([projectSlug, ns]);\n return $storage.get(hash) || {};\n };\n service.storeMyFilters = function(projectId, myFilters) {\n var deferred, hash, ns, promise, url;\n deferred = $q.defer();\n url = $urls.resolve(\"user-storage\");\n ns = \"\" + projectId + \":\" + myFiltersHashSuffix;\n hash = generateHash([projectId, ns]);\n if (_.isEmpty(myFilters)) {\n promise = $http[\"delete\"](\"\" + url + \"/\" + hash, {\n key: hash,\n value: myFilters\n });\n promise.then(function() {\n return deferred.resolve();\n });\n promise.then(null, function() {\n return deferred.reject();\n });\n } else {\n promise = $http.put(\"\" + url + \"/\" + hash, {\n key: hash,\n value: myFilters\n });\n promise.then(function(data) {\n return deferred.resolve();\n });\n promise.then(null, function(data) {\n var innerPromise;\n innerPromise = $http.post(\"\" + url, {\n key: hash,\n value: myFilters\n });\n innerPromise.then(function() {\n return deferred.resolve();\n });\n return innerPromise.then(null, function() {\n return deferred.reject();\n });\n });\n }\n return deferred.promise;\n };\n service.getMyFilters = function(projectId) {\n var deferred, hash, ns, promise, url;\n deferred = $q.defer();\n url = $urls.resolve(\"user-storage\");\n ns = \"\" + projectId + \":\" + myFiltersHashSuffix;\n hash = generateHash([projectId, ns]);\n promise = $http.get(\"\" + url + \"/\" + hash);\n promise.then(function(data) {\n return deferred.resolve(data.data.value);\n });\n promise.then(null, function(data) {\n return deferred.resolve({});\n });\n return deferred.promise;\n };\n return function(instance) {\n return instance.issues = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgIssuesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/kanban.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($storage) {\n var hashSuffixStatusColumnModes, hashSuffixStatusViewModes, service;\n service = {};\n hashSuffixStatusViewModes = \"kanban-statusviewmodels\";\n hashSuffixStatusColumnModes = \"kanban-statuscolumnmodels\";\n service.storeStatusViewModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusViewModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusViewModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusViewModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeStatusColumnModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusColumnModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n return function(instance) {\n return instance.kanban = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgKanbanResourcesProvider\", [\"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/mdrender.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service.render = function(projectId, content) {\n var params, url;\n if ((content == null) || content === \"\") {\n content = ' ';\n }\n params = {\n project_id: projectId,\n content: content\n };\n url = $urls.resolve(\"wiki\");\n return $http.post(\"\" + url + \"/render\", params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n return function(instance) {\n return instance.mdrender = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgMdRenderResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"memberships\", id);\n };\n service.list = function(projectId, filters, enablePagination) {\n var options, params;\n if (enablePagination == null) {\n enablePagination = true;\n }\n params = {\n project: projectId\n };\n params = _.extend({}, params, filters || {});\n if (enablePagination) {\n return $repo.queryPaginated(\"memberships\", params);\n }\n return $repo.queryMany(\"memberships\", params, options = {\n enablePagination: enablePagination\n });\n };\n service.listByUser = function(userId, filters) {\n var params;\n params = {\n user: userId\n };\n params = _.extend({}, params, filters || {});\n return $repo.queryPaginated(\"memberships\", params);\n };\n service.resendInvitation = function(id) {\n var url;\n url = $urls.resolve(\"memberships\");\n return $http.post(\"\" + url + \"/\" + id + \"/resend_invitation\", {});\n };\n service.bulkCreateMemberships = function(projectId, data, invitation_extra_text) {\n var params, url;\n url = $urls.resolve(\"bulk-create-memberships\");\n params = {\n project_id: projectId,\n bulk_memberships: data,\n invitation_extra_text: invitation_extra_text\n };\n return $http.post(url, params);\n };\n return function(instance) {\n return instance.memberships = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgMembershipsResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n(function() {\n var module, resourceProvider;\n\n resourceProvider = function($repo) {\n var service;\n service = {};\n service.list = function(projectId, module) {\n return $repo.queryOneAttribute(\"project-modules\", projectId, module);\n };\n return function(instance) {\n return instance.modules = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgModulesResourcesProvider\", [\"$tgRepo\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"notify-policies\", id);\n };\n service.list = function(filters) {\n var params;\n params = _.extend({}, params, filters || {});\n return $repo.queryMany(\"notify-policies\", params);\n };\n return function(instance) {\n return instance.notifyPolicies = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgNotifyPoliciesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/projects.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"projects\", id);\n };\n service.getBySlug = function(slug) {\n return $repo.queryOne(\"projects\", \"by_slug?slug=\" + slug);\n };\n service.list = function() {\n return $repo.queryMany(\"projects\");\n };\n service.templates = function() {\n return $repo.queryMany(\"project-templates\");\n };\n service.usersList = function(projectId) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(\"users\", params);\n };\n service.rolesList = function(projectId) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(\"roles\", params);\n };\n service.stats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/stats\");\n };\n service.leave = function(projectId) {\n var url;\n url = \"\" + ($urls.resolve(\"projects\")) + \"/\" + projectId + \"/leave\";\n return $http.post(url);\n };\n service.memberStats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/member_stats\");\n };\n service.tagsColors = function(id) {\n return $repo.queryOne(\"projects\", \"\" + id + \"/tags_colors\");\n };\n return function(instance) {\n return instance.projects = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgProjectsResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"roles\", id);\n };\n service.list = function(projectId) {\n return $repo.queryMany(\"roles\", {\n project: projectId\n });\n };\n return function(instance) {\n return instance.roles = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgRolesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/search.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service[\"do\"] = function(projectId, term) {\n var params, url;\n url = $urls.resolve(\"search\");\n params = {\n project: projectId,\n text: term,\n get_all: false\n };\n return $http.get(url, params).then(function(data) {\n return data.data;\n });\n };\n return function(instance) {\n return instance.search = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgSearchResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/sprints.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $model, $storage) {\n var hashSuffixUserstories, service;\n service = {};\n hashSuffixUserstories = \"userstories-queryparams\";\n service.get = function(projectId, sprintId) {\n return $repo.queryOne(\"milestones\", sprintId).then(function(sprint) {\n var uses;\n service.storeUserstoriesQueryParams(projectId, {\n \"milestone\": sprintId\n });\n uses = sprint.user_stories;\n uses = _.map(uses, function(u) {\n return $model.make_model(\"userstories\", u);\n });\n sprint._attrs.user_stories = uses;\n return sprint;\n });\n };\n service.stats = function(projectId, sprintId) {\n return $repo.queryOneRaw(\"milestones\", \"\" + sprintId + \"/stats\");\n };\n service.list = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId\n };\n params = _.extend({}, params, filters || {});\n return $repo.queryMany(\"milestones\", params).then((function(_this) {\n return function(milestones) {\n var m, uses, _i, _len;\n for (_i = 0, _len = milestones.length; _i < _len; _i++) {\n m = milestones[_i];\n uses = m.user_stories;\n uses = _.map(uses, function(u) {\n return $model.make_model(\"userstories\", u);\n });\n m._attrs.user_stories = uses;\n }\n return milestones;\n };\n })(this));\n };\n service.storeUserstoriesQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUserstories;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n return function(instance) {\n return instance.sprints = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgSprintsResourcesProvider\", [\"$tgRepo\", \"$tgModel\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/tasks.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage) {\n var hashSuffix, hashSuffixStatusColumnModes, hashSuffixUsRowModes, service;\n service = {};\n hashSuffix = \"tasks-queryparams\";\n hashSuffixStatusColumnModes = \"tasks-statuscolumnmodels\";\n hashSuffixUsRowModes = \"tasks-usrowmodels\";\n service.get = function(projectId, taskId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"tasks\", taskId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"tasks\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.list = function(projectId, sprintId, userStoryId) {\n var params;\n if (sprintId == null) {\n sprintId = null;\n }\n if (userStoryId == null) {\n userStoryId = null;\n }\n params = {\n project: projectId\n };\n if (sprintId) {\n params.milestone = sprintId;\n }\n if (userStoryId) {\n params.user_story = userStoryId;\n }\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"tasks\", params);\n };\n service.bulkCreate = function(projectId, sprintId, usId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-create-tasks\");\n params = {\n project_id: projectId,\n sprint_id: sprintId,\n us_id: usId,\n bulk_tasks: data\n };\n return $http.post(url, params).then(function(result) {\n return result.data;\n });\n };\n service.bulkUpdateTaskTaskboardOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-task-taskboard-order\");\n params = {\n project_id: projectId,\n bulk_tasks: data\n };\n return $http.post(url, params);\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeStatusColumnModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusColumnModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeUsRowModes = function(projectId, sprintId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUsRowModes;\n hash = generateHash([projectId, sprintId, ns]);\n return $storage.set(hash, params);\n };\n service.getUsRowModes = function(projectId, sprintId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUsRowModes;\n hash = generateHash([projectId, sprintId, ns]);\n return $storage.get(hash) || {};\n };\n return function(instance) {\n return instance.tasks = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgTasksResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, sizeFormat, taiga;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n resourceProvider = function($config, $repo, $http, $urls, $q) {\n var service;\n service = {};\n service.changeAvatar = function(file) {\n var data, defered, maxFileSize, options, response, url;\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize && file.size > maxFileSize) {\n response = {\n status: 413,\n data: {\n _error_message: \"'\" + file.name + \"' (\" + (sizeFormat(file.size)) + \") is too heavy for our oompa loompas, try it with a smaller than (\" + (sizeFormat(maxFileSize)) + \")\"\n }\n };\n defered = $q.defer();\n defered.reject(response);\n return defered.promise;\n }\n data = new FormData();\n data.append('avatar', file);\n options = {\n transformRequest: angular.identity,\n headers: {\n 'Content-Type': void 0\n }\n };\n url = \"\" + ($urls.resolve(\"users\")) + \"/change_avatar\";\n return $http.post(url, data, {}, options);\n };\n service.removeAvatar = function() {\n var url;\n url = \"\" + ($urls.resolve(\"users\")) + \"/remove_avatar\";\n return $http.post(url);\n };\n service.changePassword = function(currentPassword, newPassword) {\n var data, url;\n url = \"\" + ($urls.resolve(\"users\")) + \"/change_password\";\n data = {\n current_password: currentPassword,\n password: newPassword\n };\n return $http.post(url, data);\n };\n return function(instance) {\n return instance.userSettings = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgUserSettingsResourcesProvider\", [\"$tgConfig\", \"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/userstories.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage) {\n var hashSuffix, service;\n service = {};\n hashSuffix = \"userstories-queryparams\";\n service.get = function(projectId, usId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"userstories\", usId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"userstories\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.listUnassigned = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId,\n \"milestone\": \"null\"\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"userstories\", params);\n };\n service.listAll = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"userstories\", params);\n };\n service.bulkCreate = function(projectId, status, bulk) {\n var data, url;\n data = {\n project_id: projectId,\n status_id: status,\n bulk_stories: bulk\n };\n url = $urls.resolve(\"bulk-create-us\");\n return $http.post(url, data);\n };\n service.bulkUpdateBacklogOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-backlog-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.bulkUpdateSprintOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-sprint-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.bulkUpdateKanbanOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-kanban-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeShowTags = function(projectId, showTags) {\n var hash;\n hash = generateHash([projectId, 'showTags']);\n return $storage.set(hash, showTags);\n };\n service.getShowTags = function(projectId) {\n var hash;\n hash = generateHash([projectId, 'showTags']);\n return $storage.get(hash) || null;\n };\n return function(instance) {\n return instance.userstories = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgUserstoriesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/wikis.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(wikiId) {\n return $repo.queryOne(\"wiki\", wikiId);\n };\n service.getBySlug = function(projectId, slug) {\n return $repo.queryOne(\"wiki\", \"by_slug?project=\" + projectId + \"&slug=\" + slug);\n };\n service.listLinks = function(projectId) {\n return $repo.queryMany(\"wiki-links\", {\n project: projectId\n });\n };\n return function(instance) {\n return instance.wiki = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgWikiResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/main.coffee\n */\n\n(function() {\n var UserChangePasswordController, UserChangePasswordDirective, debounce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaUserSettings\");\n\n UserChangePasswordController = (function(_super) {\n __extends(UserChangePasswordController, _super);\n\n UserChangePasswordController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserChangePasswordController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, auth) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"Change Password\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserChangePasswordController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserChangePasswordController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n return UserChangePasswordController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserChangePasswordController\", UserChangePasswordController);\n\n UserChangePasswordDirective = function($rs, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs, ctrl) {\n var submit, submitButton;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if ($scope.newPassword1 !== $scope.newPassword2) {\n $confirm.notify('error', \"The passwords dosn't match\");\n return;\n }\n $loading.start(submitButton);\n promise = $rs.userSettings.changePassword($scope.currentPassword, $scope.newPassword1);\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify('success');\n });\n return promise.then(null, function(response) {\n $loading.finish(submitButton);\n return $confirm.notify('error', response.data._error_message);\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserChangePassword\", [\"$tgResources\", \"$tgConfirm\", \"$tgLoading\", UserChangePasswordDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/lightboxes.coffee\n */\n\n(function() {\n var DeleteUserDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaUserSettings\");\n\n DeleteUserDirective = function($repo, $rootscope, $auth, $location, $navUrls, lightboxService) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit;\n $scope.$on(\"deletelightbox:new\", function(ctx, user) {\n return lightboxService.open($el);\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = function() {\n var promise;\n promise = $repo.remove($scope.user);\n promise.then(function(data) {\n lightboxService.close($el);\n $auth.logout();\n return $location.path($navUrls.resolve(\"login\"));\n });\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n $el.on(\"click\", \".button-red\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n return $el.on(\"click\", \".button-green\", debounce(2000, function(event) {\n event.preventDefault();\n return submit();\n }));\n };\n return {\n link: link,\n templateUrl: \"/partials/views/modules/lightbox-delete-account.html\"\n };\n };\n\n module.directive(\"tgLbDeleteUser\", [\"$tgRepo\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"lightboxService\", DeleteUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/main.coffee\n */\n\n(function() {\n var TaigaAvatarModelDirective, UserAvatarDirective, UserProfileDirective, UserSettingsController, debounce, mixOf, module, sizeFormat, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n sizeFormat = this.taiga.sizeFormat;\n\n module = angular.module(\"taigaUserSettings\");\n\n debounce = this.taiga.debounce;\n\n UserSettingsController = (function(_super) {\n __extends(UserSettingsController, _super);\n\n UserSettingsController.$inject = [\"$scope\", \"$rootScope\", \"$tgConfig\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserSettingsController(scope, rootscope, config, repo, confirm, rs, params, q, location, navUrls, auth) {\n var maxFileSize, promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.config = config;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"User Profile\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n maxFileSize = this.config.get(\"maxUploadFileSize\", null);\n if (maxFileSize) {\n this.scope.maxFileSizeMsg = \"[Max, size: \" + (sizeFormat(maxFileSize));\n }\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserSettingsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserSettingsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n UserSettingsController.prototype.openDeleteLightbox = function() {\n return this.rootscope.$broadcast(\"deletelightbox:new\", this.scope.user);\n };\n\n return UserSettingsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserSettingsController\", UserSettingsController);\n\n UserProfileDirective = function($confirm, $auth, $repo) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var changeEmail, form, onError, onSuccess;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n changeEmail = $scope.user.isAttributeModified(\"email\");\n onSuccess = function(data) {\n $auth.setUser($scope.user);\n if (changeEmail) {\n return $confirm.success(\"Check your inbox!
    We have sent a mail to your account
    with the instructions to set your new address\");\n } else {\n return $confirm.notify('success');\n }\n };\n onError = function(data) {\n form.setErrors(data);\n return $confirm.notify('error', data._error_message);\n };\n return $repo.save($scope.user).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserProfile\", [\"$tgConfirm\", \"$tgAuth\", \"$tgRepo\", UserProfileDirective]);\n\n UserAvatarDirective = function($auth, $model, $rs, $confirm) {\n var link;\n link = function($scope, $el, $attrs) {\n var onError, onSuccess, showSizeInfo;\n showSizeInfo = function() {\n return $el.find(\".size-info\").removeClass(\"hidden\");\n };\n onSuccess = function(response) {\n var user;\n user = $model.make_model(\"users\", response.data);\n $auth.setUser(user);\n $scope.user = user;\n $el.find('.overlay').hide();\n return $confirm.notify('success');\n };\n onError = function(response) {\n if (response.status === 413) {\n showSizeInfo();\n }\n $el.find('.overlay').hide();\n return $confirm.notify('error', response.data._error_message);\n };\n $el.on(\"click\", \".button.change\", function() {\n return $el.find(\"#avatar-field\").click();\n });\n $el.on(\"change\", \"#avatar-field\", function(event) {\n if ($scope.avatarAttachment) {\n $el.find('.overlay').show();\n return $rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess, onError);\n }\n });\n $el.on(\"click\", \"a.use-gravatar\", function(event) {\n $el.find('.overlay').show();\n return $rs.userSettings.removeAvatar().then(onSuccess, onError);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserAvatar\", [\"$tgAuth\", \"$tgModel\", \"$tgResources\", \"$tgConfirm\", UserAvatarDirective]);\n\n TaigaAvatarModelDirective = function($parse) {\n var link;\n link = function($scope, $el, $attrs) {\n var model, modelSetter;\n model = $parse($attrs.tgAvatarModel);\n modelSetter = model.assign;\n return $el.bind('change', function() {\n return $scope.$apply(function() {\n return modelSetter($scope, $el[0].files[0]);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive('tgAvatarModel', ['$parse', TaigaAvatarModelDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/nav.coffee\n */\n\n(function() {\n var UserSettingsNavigationDirective, module;\n\n UserSettingsNavigationDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var section;\n section = $attrs.tgUserSettingsNavigation;\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\"#usersettingsmenu-\" + section + \" a\").addClass(\"active\");\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaUserSettings\");\n\n module.directive(\"tgUserSettingsNavigation\", UserSettingsNavigationDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/notifications.coffee\n */\n\n(function() {\n var UserNotificationsController, UserNotificationsDirective, UserNotificationsListDirective, bindOnce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaUserSettings\");\n\n UserNotificationsController = (function(_super) {\n __extends(UserNotificationsController, _super);\n\n UserNotificationsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserNotificationsController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, auth) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"Email Notifications\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserNotificationsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserNotificationsController.prototype.loadNotifyPolicies = function() {\n return this.rs.notifyPolicies.list().then((function(_this) {\n return function(notifyPolicies) {\n _this.scope.notifyPolicies = notifyPolicies;\n return notifyPolicies;\n };\n })(this));\n };\n\n UserNotificationsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadNotifyPolicies();\n };\n })(this));\n };\n\n return UserNotificationsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserNotificationsController\", UserNotificationsController);\n\n UserNotificationsDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserNotifications\", UserNotificationsDirective);\n\n UserNotificationsListDirective = function($repo, $confirm) {\n var link, template;\n template = _.template(\"<% _.each(notifyPolicies, function (notifyPolicy, index) { %>\\n
    \\\">\\n
    <%- notifyPolicy.project_name %>
    \\n
    \\n
    \\n \\\" id=\\\"policy-all-<%- notifyPolicy.id %>\\\"\\n value=\\\"2\\\" <% if (notifyPolicy.notify_level == 2) { %>checked=\\\"checked\\\"<% } %>/>\\n \\n
    \\n
    \\n
    \\n
    \\n \\\" id=\\\"policy-involved-<%- notifyPolicy.id %>\\\"\\n value=\\\"1\\\" <% if (notifyPolicy.notify_level == 1) { %>checked=\\\"checked\\\"<% } %> />\\n \\n
    \\n
    \\n
    \\n
    \\n \\\" id=\\\"policy-none-<%- notifyPolicy.id %>\\\"\\n value=\\\"3\\\" <% if (notifyPolicy.notify_level == 3) { %>checked=\\\"checked\\\"<% } %> />\\n \\n
    \\n
    \\n
    \\n<% }) %>\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function() {\n $el.off();\n $el.html(template({\n notifyPolicies: $scope.notifyPolicies\n }));\n return $el.on(\"change\", \"input[type=radio]\", function(event) {\n var onError, onSuccess, policy, policyIndex, prev_level, target;\n target = angular.element(event.currentTarget);\n policyIndex = target.parents(\".policy-table-row\").data('index');\n policy = $scope.notifyPolicies[policyIndex];\n prev_level = policy.notify_level;\n policy.notify_level = parseInt(target.val(), 10);\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n return target.parents(\".policy-table-row\").find(\"input[value=\" + prev_level + \"]\").prop(\"checked\", true);\n };\n return $repo.save(policy).then(onSuccess, onError);\n });\n };\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return bindOnce($scope, $attrs.ngModel, render);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserNotificationsList\", [\"$tgRepo\", \"$tgConfirm\", UserNotificationsListDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/integrations/github.coffee\n */\n\n(function() {\n var AUTH_URL, GithubLoginButtonDirective, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaIntegrations\");\n\n AUTH_URL = \"https://github.com/login/oauth/authorize\";\n\n GithubLoginButtonDirective = function($window, $params, $location, $config, $events, $confirm, $auth, $navUrls, $loader) {\n var link, template;\n template = \"\\n \\n Login with Github\\n\";\n link = function($scope, $el, $attrs) {\n var clientId, loginOnError, loginOnSuccess, loginWithGitHubAccount, renderGitHubButton;\n clientId = $config.get(\"gitHubClientId\", null);\n if (!clientId) {\n return;\n }\n renderGitHubButton = function() {\n if (clientId) {\n return $el.html(template);\n }\n };\n loginOnSuccess = function(response) {\n var nextUrl;\n if ($params.next && $params.next !== $navUrls.resolve(\"login\")) {\n nextUrl = $params.next;\n } else {\n nextUrl = $navUrls.resolve(\"home\");\n }\n $events.setupConnection();\n $location.search(\"next\", null);\n $location.search(\"token\", null);\n $location.search(\"state\", null);\n $location.search(\"code\", null);\n return $location.path(nextUrl);\n };\n loginOnError = function(response) {\n $location.search(\"state\", null);\n $location.search(\"code\", null);\n $loader.pageLoaded();\n if (response.data.error_message) {\n return $confirm.notify(\"light-error\", response.data.error_message);\n } else {\n return $confirm.notify(\"light-error\", \"Our Oompa Loompas have not been able to get you credentials from GitHub.\");\n }\n };\n loginWithGitHubAccount = function() {\n var code, data, token, type;\n type = $params.state;\n code = $params.code;\n token = $params.token;\n if (!(type === \"github\" && code)) {\n return;\n }\n $loader.start();\n data = {\n code: code,\n token: token\n };\n return $auth.login(data, type).then(loginOnSuccess, loginOnError);\n };\n renderGitHubButton();\n loginWithGitHubAccount();\n $el.on(\"click\", \".button-github\", function(event) {\n var redirectToUri, url;\n redirectToUri = $location.absUrl();\n url = \"\" + AUTH_URL + \"?client_id=\" + clientId + \"&redirect_uri=\" + redirectToUri + \"&state=github&scope=user:email\";\n return $window.location.href = url;\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n template: \"\"\n };\n };\n\n module.directive(\"tgGithubLoginButton\", [\"$window\", '$routeParams', \"$tgLocation\", \"$tgConfig\", \"$tgEvents\", \"$tgConfirm\", \"$tgAuth\", \"$tgNavUrls\", \"tgLoader\", GithubLoginButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: plugins/humanshtml/humanshtml.coffee\n */\n\n(function() {\n var configure, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n configure = function($routeProvider) {\n return $routeProvider.when(\"/humans.html\", {\n \"templateUrl\": \"/plugins/humanshtml/templates/humans.html\"\n });\n };\n\n module.config([\"$routeProvider\", configure]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: plugins/terms/terms.coffee\n */\n\n(function() {\n var TermsNoticeDirective, module, taiga, template;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n template = _.template(\"

    \\n By clicking \\\"Sign up\\\", you agree to our
    \\n \\\" title=\\\"See terms of service\\\" target=\\\"_blank\\\"> terms of service\\n and\\n \\\" title=\\\"See privacy policy\\\" target=\\\"_blank\\\"> privacy policy.\\n

    \");\n\n TermsNoticeDirective = function($config) {\n var privacyPolicyUrl, templateFn, termsOfServiceUrl;\n privacyPolicyUrl = $config.get(\"privacyPolicyUrl\");\n termsOfServiceUrl = $config.get(\"termsOfServiceUrl\");\n templateFn = function() {\n var ctx;\n if (!(privacyPolicyUrl && termsOfServiceUrl)) {\n return \"\";\n }\n ctx = {\n termsUrl: termsOfServiceUrl,\n privacyUrl: privacyPolicyUrl\n };\n return template(ctx);\n };\n return {\n scope: {},\n restrict: \"AE\",\n template: templateFn\n };\n };\n\n module.directive(\"tgTermsNotice\", [\"$tgConfig\", TermsNoticeDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: pluggins/main.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n}).call(this);\n","angular.module('taigaBase').value('localesEn', {\n \"checksley\": {\n \"defaultMessage\": \"This value seems to be invalid.\",\n \"type-email\": \"This value should be a valid email.\",\n \"type-url\": \"This value should be a valid url.\",\n \"type-urlstrict\": \"This value should be a valid url.\",\n \"type-number\": \"This value should be a valid number.\",\n \"type-digits\": \"This value should be digits.\",\n \"type-dateIso\": \"This value should be a valid date (YYYY-MM-DD).\",\n \"type-alphanum\": \"This value should be alphanumeric.\",\n \"type-phone\": \"This value should be a valid phone number.\",\n \"notnull\": \"This value should not be null.\",\n \"notblank\": \"This value should not be blank.\",\n \"required\": \"This value is required.\",\n \"regexp\": \"This value seems to be invalid.\",\n \"min\": \"This value should be greater than or equal to %s.\",\n \"max\": \"This value should be lower than or equal to %s.\",\n \"range\": \"This value should be between %s and %s.\",\n \"minlength\": \"This value is too short. It should have %s characters or more.\",\n \"maxlength\": \"This value is too long. It should have %s characters or less.\",\n \"rangelength\": \"This value length is invalid. It should be between %s and %s characters long.\",\n \"mincheck\": \"You must select at least %s choices.\",\n \"maxcheck\": \"You must select %s choices or less.\",\n \"rangecheck\": \"You must select between %s and %s choices.\",\n \"equalto\": \"This value should be the same.\"\n },\n \"common\": {\n \"subject\": \"Subject\",\n \"save\": \"Save\",\n \"blocked\": \"Blocked\",\n \"cancel\": \"Cancel\",\n \"status\": \"Status\",\n \"new-bulk\": \"New bulk insert\",\n \"one-item-line\": \"One item per line...\"\n },\n \"pagination\": {\n \"next\": \"Next\",\n \"prev\": \"Previous\"\n },\n \"markdown-editor\": {\n \"heading-1\": \"First Level Heading\",\n \"heading-2\": \"Second Level Heading\",\n \"heading-3\": \"Third Level Heading\",\n \"bold\": \"Bold\",\n \"italic\": \"Italic\",\n \"strike\": \"Strike\",\n \"bulleted-list\": \"Bulleted List\",\n \"numeric-list\": \"Numeric List\",\n \"picture\": \"Picture\",\n \"link\": \"Link\",\n \"quotes\": \"Quotes\",\n \"code-block\": \"Code Block / Code\",\n \"preview\": \"Preview\",\n \"help\": \"Help\",\n \"placeholder\": \"Your title here...\",\n \"link-placeholder\": \"Your text to link here...\"\n },\n \"us\": {\n \"title-new\": \"New User Story\",\n \"team-requirement\": \"Team Requirement\",\n \"client-requirement\": \"Client Requirement\"\n }\n}\n);"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["app.js","locales.en.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACz/qBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"app.js","sourcesContent":["\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: app.coffee\n */\n\n(function() {\n var configure, init, module, modules, taiga;\n\n this.taiga = taiga = {};\n\n this.taigaContribPlugins = this.taigaContribPlugins || [];\n\n taiga.generateHash = function(components) {\n if (components == null) {\n components = [];\n }\n components = _.map(components, function(x) {\n return JSON.stringify(x);\n });\n return hex_sha1(components.join(\":\"));\n };\n\n taiga.generateUniqueSessionIdentifier = function() {\n var date, randomNumber;\n date = (new Date()).getTime();\n randomNumber = Math.floor(Math.random() * 0x9000000);\n return taiga.generateHash([date, randomNumber]);\n };\n\n taiga.sessionId = taiga.generateUniqueSessionIdentifier();\n\n configure = function($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider) {\n var authHttpIntercept, defaultHeaders, versionCheckHttpIntercept;\n $routeProvider.when(\"/\", {\n templateUrl: \"project/projects.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/\", {\n templateUrl: \"project/project.html\"\n });\n $routeProvider.when(\"/project/:pslug/backlog\", {\n templateUrl: \"backlog/backlog.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/taskboard/:sslug\", {\n templateUrl: \"taskboard/taskboard.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/search\", {\n templateUrl: \"search/search.html\",\n reloadOnSearch: false\n });\n $routeProvider.when(\"/project/:pslug/kanban\", {\n templateUrl: \"kanban/kanban.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/us/:usref\", {\n templateUrl: \"us/us-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/task/:taskref\", {\n templateUrl: \"task/task-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/wiki\", {\n redirectTo: function(params) {\n return \"/project/\" + params.pslug + \"/wiki/home\";\n }\n });\n $routeProvider.when(\"/project/:pslug/wiki/:slug\", {\n templateUrl: \"wiki/wiki.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/team\", {\n templateUrl: \"team/team.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/issues\", {\n templateUrl: \"issue/issues.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/issue/:issueref\", {\n templateUrl: \"issue/issues-detail.html\",\n resolve: {\n loader: tgLoaderProvider.add()\n }\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/details\", {\n templateUrl: \"admin/admin-project-profile.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/default-values\", {\n templateUrl: \"admin/admin-project-default-values.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/modules\", {\n templateUrl: \"admin/admin-project-modules.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-profile/export\", {\n templateUrl: \"admin/admin-project-export.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/us-status\", {\n templateUrl: \"admin/admin-project-values-us-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/us-points\", {\n templateUrl: \"admin/admin-project-values-us-points.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/task-status\", {\n templateUrl: \"admin/admin-project-values-task-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-status\", {\n templateUrl: \"admin/admin-project-values-issue-status.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-types\", {\n templateUrl: \"admin/admin-project-values-issue-types.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-priorities\", {\n templateUrl: \"admin/admin-project-values-issue-priorities.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/project-values/issue-severities\", {\n templateUrl: \"admin/admin-project-values-issue-severities.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/memberships\", {\n templateUrl: \"admin/admin-memberships.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/roles\", {\n templateUrl: \"admin/admin-roles.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/webhooks\", {\n templateUrl: \"admin/admin-third-parties-webhooks.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/github\", {\n templateUrl: \"admin/admin-third-parties-github.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/gitlab\", {\n templateUrl: \"admin/admin-third-parties-gitlab.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/third-parties/bitbucket\", {\n templateUrl: \"admin/admin-third-parties-bitbucket.html\"\n });\n $routeProvider.when(\"/project/:pslug/admin/contrib/:plugin\", {\n templateUrl: \"contrib/main.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-profile\", {\n templateUrl: \"user/user-profile.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-change-password\", {\n templateUrl: \"user/user-change-password.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/user-avatar\", {\n templateUrl: \"user/user-avatar.html\"\n });\n $routeProvider.when(\"/project/:pslug/user-settings/mail-notifications\", {\n templateUrl: \"user/mail-notifications.html\"\n });\n $routeProvider.when(\"/change-email/:email_token\", {\n templateUrl: \"user/change-email.html\"\n });\n $routeProvider.when(\"/cancel-account/:cancel_token\", {\n templateUrl: \"user/cancel-account.html\"\n });\n $routeProvider.when(\"/login\", {\n templateUrl: \"auth/login.html\"\n });\n $routeProvider.when(\"/register\", {\n templateUrl: \"auth/register.html\"\n });\n $routeProvider.when(\"/forgot-password\", {\n templateUrl: \"auth/forgot-password.html\"\n });\n $routeProvider.when(\"/change-password\", {\n templateUrl: \"auth/change-password-from-recovery.html\"\n });\n $routeProvider.when(\"/change-password/:token\", {\n templateUrl: \"auth/change-password-from-recovery.html\"\n });\n $routeProvider.when(\"/invitation/:token\", {\n templateUrl: \"auth/invitation.html\"\n });\n $routeProvider.when(\"/error\", {\n templateUrl: \"error/error.html\"\n });\n $routeProvider.when(\"/not-found\", {\n templateUrl: \"error/not-found.html\"\n });\n $routeProvider.when(\"/permission-denied\", {\n templateUrl: \"error/permission-denied.html\"\n });\n $routeProvider.otherwise({\n redirectTo: '/not-found'\n });\n $locationProvider.html5Mode({\n enabled: true,\n requireBase: false\n });\n defaultHeaders = {\n \"Content-Type\": \"application/json\",\n \"Accept-Language\": \"en\",\n \"X-Session-Id\": taiga.sessionId\n };\n $httpProvider.defaults.headers[\"delete\"] = defaultHeaders;\n $httpProvider.defaults.headers.patch = defaultHeaders;\n $httpProvider.defaults.headers.post = defaultHeaders;\n $httpProvider.defaults.headers.put = defaultHeaders;\n $httpProvider.defaults.headers.get = {\n \"X-Session-Id\": taiga.sessionId\n };\n $tgEventsProvider.setSessionId(taiga.sessionId);\n authHttpIntercept = function($q, $location, $navUrls, $lightboxService) {\n var httpResponseError;\n httpResponseError = function(response) {\n var nextPath;\n if (response.status === 0) {\n $lightboxService.closeAll();\n $location.path($navUrls.resolve(\"error\"));\n $location.replace();\n } else if (response.status === 401) {\n nextPath = $location.path();\n $location.url($navUrls.resolve(\"login\")).search(\"next=\" + nextPath);\n }\n return $q.reject(response);\n };\n return {\n responseError: httpResponseError\n };\n };\n $provide.factory(\"authHttpIntercept\", [\"$q\", \"$location\", \"$tgNavUrls\", \"lightboxService\", authHttpIntercept]);\n $httpProvider.interceptors.push('authHttpIntercept');\n versionCheckHttpIntercept = function($q, $confirm) {\n var httpResponseError, versionErrorMsg;\n versionErrorMsg = \"Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost).\";\n httpResponseError = function(response) {\n if (response.status === 400 && response.data.version) {\n $confirm.notify(\"error\", versionErrorMsg, null, 10000);\n return $q.reject(response);\n }\n return $q.reject(response);\n };\n return {\n responseError: httpResponseError\n };\n };\n $provide.factory(\"versionCheckHttpIntercept\", [\"$q\", \"$tgConfirm\", versionCheckHttpIntercept]);\n $httpProvider.interceptors.push('versionCheckHttpIntercept');\n window.checksley.updateValidators({\n linewidth: function(val, width) {\n var lines, valid;\n lines = taiga.nl2br(val).split(\"
    \");\n valid = _.every(lines, function(line) {\n return line.length < width;\n });\n return valid;\n }\n });\n return window.checksley.updateMessages(\"default\", {\n linewidth: \"The subject must have a maximum size of %s\"\n });\n };\n\n init = function($log, $i18n, $config, $rootscope, $auth, $events, $analytics) {\n $i18n.initialize($config.get(\"defaultLanguage\"));\n $log.debug(\"Initialize application\");\n $rootscope.contribPlugins = this.taigaContribPlugins;\n if ($auth.isAuthenticated()) {\n $events.setupConnection();\n }\n return $analytics.initialize();\n };\n\n modules = [\"taigaBase\", \"taigaCommon\", \"taigaResources\", \"taigaLocales\", \"taigaAuth\", \"taigaEvents\", \"taigaRelatedTasks\", \"taigaBacklog\", \"taigaTaskboard\", \"taigaKanban\", \"taigaIssues\", \"taigaUserStories\", \"taigaTasks\", \"taigaTeam\", \"taigaWiki\", \"taigaSearch\", \"taigaAdmin\", \"taigaNavMenu\", \"taigaProject\", \"taigaUserSettings\", \"taigaFeedback\", \"taigaPlugins\", \"taigaIntegrations\", \"templates\", \"ngRoute\", \"ngAnimate\"].concat(_.map(this.taigaContribPlugins, function(plugin) {\n return plugin.module;\n }));\n\n module = angular.module(\"taiga\", modules);\n\n module.config([\"$routeProvider\", \"$locationProvider\", \"$httpProvider\", \"$provide\", \"$tgEventsProvider\", \"tgLoaderProvider\", configure]);\n\n module.run([\"$log\", \"$tgI18n\", \"$tgConfig\", \"$rootScope\", \"$tgAuth\", \"$tgEvents\", \"$tgAnalytics\", init]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: classes.coffee\n */\n\n(function() {\n var TaigaBase, TaigaController, TaigaService,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };\n\n TaigaBase = (function() {\n function TaigaBase() {}\n\n return TaigaBase;\n\n })();\n\n TaigaService = (function(_super) {\n __extends(TaigaService, _super);\n\n function TaigaService() {\n return TaigaService.__super__.constructor.apply(this, arguments);\n }\n\n return TaigaService;\n\n })(TaigaBase);\n\n TaigaController = (function(_super) {\n __extends(TaigaController, _super);\n\n function TaigaController() {\n this.onInitialDataError = __bind(this.onInitialDataError, this);\n return TaigaController.__super__.constructor.apply(this, arguments);\n }\n\n TaigaController.prototype.onInitialDataError = function(xhr) {\n if (xhr) {\n if (xhr.status === 404) {\n this.location.path(this.navUrls.resolve(\"not-found\"));\n this.location.replace();\n } else if (xhr.status === 403) {\n this.location.path(this.navUrls.resolve(\"permission-denied\"));\n this.location.replace();\n }\n }\n return this.q.reject(xhr);\n };\n\n return TaigaController;\n\n })(TaigaBase);\n\n this.taiga.Base = TaigaBase;\n\n this.taiga.Service = TaigaService;\n\n this.taiga.Controller = TaigaController;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: utils.coffee\n */\n\n(function() {\n var bindMethods, bindOnce, cancelTimeout, debounce, debounceLeading, groupBy, joinStr, mixOf, nl2br, scopeDefer, sizeFormat, slugify, startswith, taiga, timeout, toString, toggleText, trim, unslugify,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },\n __slice = [].slice,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n nl2br = (function(_this) {\n return function(str) {\n var breakTag;\n breakTag = '
    ';\n return (str + '').replace(/([^>\\r\\n]?)(\\r\\n|\\n\\r|\\r|\\n)/g, '$1' + breakTag + '$2');\n };\n })(this);\n\n bindMethods = (function(_this) {\n return function(object) {\n var dependencies, methods;\n dependencies = _.keys(object);\n methods = [];\n _.forIn(object, function(value, key) {\n if (__indexOf.call(dependencies, key) < 0) {\n return methods.push(key);\n }\n });\n return _.bindAll(object, methods);\n };\n })(this);\n\n bindOnce = (function(_this) {\n return function(scope, attr, continuation) {\n var delBind, val;\n val = scope.$eval(attr);\n if (val !== void 0) {\n return continuation(val);\n }\n delBind = null;\n return delBind = scope.$watch(attr, function(val) {\n if (val === void 0) {\n return;\n }\n continuation(val);\n if (delBind) {\n return delBind();\n }\n });\n };\n })(this);\n\n mixOf = function() {\n var Mixed, base, method, mixin, mixins, name, _i, _ref;\n base = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n Mixed = (function(_super) {\n __extends(Mixed, _super);\n\n function Mixed() {\n return Mixed.__super__.constructor.apply(this, arguments);\n }\n\n return Mixed;\n\n })(base);\n for (_i = mixins.length - 1; _i >= 0; _i += -1) {\n mixin = mixins[_i];\n _ref = mixin.prototype;\n for (name in _ref) {\n method = _ref[name];\n Mixed.prototype[name] = method;\n }\n }\n return Mixed;\n };\n\n trim = function(data, char) {\n return _.str.trim(data, char);\n };\n\n slugify = function(data) {\n return _.str.slugify(data);\n };\n\n unslugify = function(data) {\n if (data) {\n return _.str.capitalize(data.replace(/-/g, ' '));\n }\n return data;\n };\n\n toggleText = function(element, texts) {\n var nextTextPosition, text;\n nextTextPosition = element.data('nextTextPosition');\n if ((nextTextPosition == null) || nextTextPosition >= texts.length) {\n nextTextPosition = 0;\n }\n text = texts[nextTextPosition];\n element.data('nextTextPosition', nextTextPosition + 1);\n return element.text(text);\n };\n\n groupBy = function(coll, pred) {\n var item, result, _i, _len;\n result = {};\n for (_i = 0, _len = coll.length; _i < _len; _i++) {\n item = coll[_i];\n result[pred(item)] = item;\n }\n return result;\n };\n\n timeout = function(wait, continuation) {\n return window.setTimeout(continuation, wait);\n };\n\n cancelTimeout = function(timeoutVar) {\n return window.clearTimeout(timeoutVar);\n };\n\n scopeDefer = function(scope, func) {\n return _.defer((function(_this) {\n return function() {\n return scope.$apply(func);\n };\n })(this));\n };\n\n toString = function(value) {\n if (_.isNumber(value)) {\n return value + \"\";\n } else if (_.isString(value)) {\n return value;\n } else if (_.isPlainObject(value)) {\n return JSON.stringify(value);\n } else if (_.isUndefined(value)) {\n return \"\";\n }\n return value.toString();\n };\n\n joinStr = function(str, coll) {\n return _.str.join(str, coll);\n };\n\n debounce = function(wait, func) {\n return _.debounce(func, wait, {\n leading: true,\n trailing: false\n });\n };\n\n debounceLeading = function(wait, func) {\n return _.debounce(func, wait, {\n leading: false,\n trailing: true\n });\n };\n\n startswith = function(str1, str2) {\n return _.str.startsWith(str1, str2);\n };\n\n sizeFormat = function(input, precision) {\n var number, size, units;\n if (precision == null) {\n precision = 1;\n }\n if (isNaN(parseFloat(input)) || !isFinite(input)) {\n return \"-\";\n }\n if (input === 0) {\n return \"0 bytes\";\n }\n units = [\"bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n number = Math.floor(Math.log(input) / Math.log(1024));\n if (number > 5) {\n number = 5;\n }\n size = (input / Math.pow(1024, number)).toFixed(precision);\n return \"\" + size + \" \" + units[number];\n };\n\n taiga = this.taiga;\n\n taiga.nl2br = nl2br;\n\n taiga.bindMethods = bindMethods;\n\n taiga.bindOnce = bindOnce;\n\n taiga.mixOf = mixOf;\n\n taiga.trim = trim;\n\n taiga.slugify = slugify;\n\n taiga.unslugify = unslugify;\n\n taiga.toggleText = toggleText;\n\n taiga.groupBy = groupBy;\n\n taiga.timeout = timeout;\n\n taiga.cancelTimeout = cancelTimeout;\n\n taiga.scopeDefer = scopeDefer;\n\n taiga.toString = toString;\n\n taiga.joinStr = joinStr;\n\n taiga.debounce = debounce;\n\n taiga.debounceLeading = debounceLeading;\n\n taiga.startswith = startswith;\n\n taiga.sizeFormat = sizeFormat;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/controllerMixins.coffee\n */\n\n(function() {\n var FiltersMixin, PageMixin, groupBy, joinStr, taiga, toString, trim;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n joinStr = this.taiga.joinStr;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n PageMixin = (function() {\n function PageMixin() {}\n\n PageMixin.prototype.fillUsersAndRoles = function(users, roles) {\n var activeUsers, availableRoles;\n activeUsers = _.filter(users, (function(_this) {\n return function(user) {\n return user.is_active;\n };\n })(this));\n this.scope.activeUsers = _.sortBy(activeUsers, \"full_name_display\");\n this.scope.activeUsersById = groupBy(this.scope.activeUsers, function(e) {\n return e.id;\n });\n this.scope.users = _.sortBy(users, \"full_name_display\");\n this.scope.usersById = groupBy(this.scope.users, function(e) {\n return e.id;\n });\n this.scope.roles = _.sortBy(roles, \"order\");\n availableRoles = _(this.scope.project.memberships).map(\"role\").uniq().value();\n return this.scope.computableRoles = _(roles).filter(\"computable\").filter(function(x) {\n return _.contains(availableRoles, x.id);\n }).value();\n };\n\n PageMixin.prototype.loadUsersAndRoles = function() {\n var promise;\n promise = this.q.all([this.rs.projects.usersList(this.scope.projectId), this.rs.projects.rolesList(this.scope.projectId)]);\n return promise.then((function(_this) {\n return function(results) {\n var roles, users;\n users = results[0], roles = results[1];\n _this.fillUsersAndRoles(users, roles);\n return results;\n };\n })(this));\n };\n\n return PageMixin;\n\n })();\n\n taiga.PageMixin = PageMixin;\n\n FiltersMixin = (function() {\n function FiltersMixin() {}\n\n FiltersMixin.prototype.selectFilter = function(name, value, load) {\n var existing, location, params;\n if (load == null) {\n load = false;\n }\n params = this.location.search();\n if (params[name] !== void 0 && name !== \"page\") {\n existing = _.map(taiga.toString(params[name]).split(\",\"), function(x) {\n return trim(x);\n });\n existing.push(taiga.toString(value));\n existing = _.compact(existing);\n value = joinStr(\",\", _.uniq(existing));\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n FiltersMixin.prototype.replaceFilter = function(name, value, load) {\n var location;\n if (load == null) {\n load = false;\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n FiltersMixin.prototype.replaceAllFilters = function(filters, load) {\n var location;\n if (load == null) {\n load = false;\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(filters);\n };\n\n FiltersMixin.prototype.unselectFilter = function(name, value, load) {\n var location, newValues, params, parsedValues;\n if (load == null) {\n load = false;\n }\n params = this.location.search();\n if (params[name] === void 0) {\n return;\n }\n if (value === void 0 || value === null) {\n delete params[name];\n }\n parsedValues = _.map(taiga.toString(params[name]).split(\",\"), function(x) {\n return trim(x);\n });\n newValues = _.reject(parsedValues, function(x) {\n return x === taiga.toString(value);\n });\n newValues = _.compact(newValues);\n if (_.isEmpty(newValues)) {\n value = null;\n } else {\n value = joinStr(\",\", _.uniq(newValues));\n }\n location = load ? this.location : this.location.noreload(this.scope);\n return location.search(name, value);\n };\n\n return FiltersMixin;\n\n })();\n\n taiga.FiltersMixin = FiltersMixin;\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaAdmin\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/auth.coffee\n */\n\n(function() {\n var AuthService, CancelAccountDirective, ChangeEmailDirective, ChangePasswordFromRecoveryDirective, ForgotPasswordDirective, InvitationDirective, LoginDirective, PublicRegisterMessageDirective, RegisterDirective, debounce, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAuth\", [\"taigaResources\"]);\n\n AuthService = (function(_super) {\n __extends(AuthService, _super);\n\n AuthService.$inject = [\"$rootScope\", \"$tgStorage\", \"$tgModel\", \"$tgResources\", \"$tgHttp\", \"$tgUrls\"];\n\n function AuthService(rootscope, storage, model, rs, http, urls) {\n this.rootscope = rootscope;\n this.storage = storage;\n this.model = model;\n this.rs = rs;\n this.http = http;\n this.urls = urls;\n AuthService.__super__.constructor.call(this);\n }\n\n AuthService.prototype.getUser = function() {\n var user, userData;\n if (this.rootscope.user) {\n return this.rootscope.user;\n }\n userData = this.storage.get(\"userInfo\");\n if (userData) {\n user = this.model.make_model(\"users\", userData);\n this.rootscope.user = user;\n return user;\n }\n return null;\n };\n\n AuthService.prototype.setUser = function(user) {\n this.rootscope.auth = user;\n this.rootscope.$broadcast(\"i18n:change\", user.default_language);\n this.storage.set(\"userInfo\", user.getAttrs());\n return this.rootscope.user = user;\n };\n\n AuthService.prototype.clear = function() {\n this.rootscope.auth = null;\n this.rootscope.user = null;\n return this.storage.remove(\"userInfo\");\n };\n\n AuthService.prototype.setToken = function(token) {\n return this.storage.set(\"token\", token);\n };\n\n AuthService.prototype.getToken = function() {\n return this.storage.get(\"token\");\n };\n\n AuthService.prototype.removeToken = function() {\n return this.storage.remove(\"token\");\n };\n\n AuthService.prototype.isAuthenticated = function() {\n if (this.getUser() !== null) {\n return true;\n }\n return false;\n };\n\n AuthService.prototype.login = function(data, type) {\n var url;\n url = this.urls.resolve(\"auth\");\n data = _.clone(data, false);\n data.type = type ? type : \"normal\";\n this.removeToken();\n return this.http.post(url, data).then((function(_this) {\n return function(data, status) {\n var user;\n user = _this.model.make_model(\"users\", data.data);\n _this.setToken(user.auth_token);\n _this.setUser(user);\n return user;\n };\n })(this));\n };\n\n AuthService.prototype.logout = function() {\n this.removeToken();\n return this.clear();\n };\n\n AuthService.prototype.register = function(data, type, existing) {\n var url;\n url = this.urls.resolve(\"auth-register\");\n data = _.clone(data, false);\n data.type = type ? type : \"public\";\n if (type === \"private\") {\n data.existing = existing ? existing : false;\n }\n this.removeToken();\n return this.http.post(url, data).then((function(_this) {\n return function(response) {\n var user;\n user = _this.model.make_model(\"users\", response.data);\n _this.setToken(user.auth_token);\n _this.setUser(user);\n return user;\n };\n })(this));\n };\n\n AuthService.prototype.getInvitation = function(token) {\n return this.rs.invitations.get(token);\n };\n\n AuthService.prototype.acceptInvitiationWithNewUser = function(data) {\n return this.register(data, \"private\", false);\n };\n\n AuthService.prototype.acceptInvitiationWithExistingUser = function(data) {\n return this.register(data, \"private\", true);\n };\n\n AuthService.prototype.forgotPassword = function(data) {\n var url;\n url = this.urls.resolve(\"users-password-recovery\");\n data = _.clone(data, false);\n this.removeToken();\n return this.http.post(url, data);\n };\n\n AuthService.prototype.changePasswordFromRecovery = function(data) {\n var url;\n url = this.urls.resolve(\"users-change-password-from-recovery\");\n data = _.clone(data, false);\n this.removeToken();\n return this.http.post(url, data);\n };\n\n AuthService.prototype.changeEmail = function(data) {\n var url;\n url = this.urls.resolve(\"users-change-email\");\n data = _.clone(data, false);\n return this.http.post(url, data);\n };\n\n AuthService.prototype.cancelAccount = function(data) {\n var url;\n url = this.urls.resolve(\"users-cancel-account\");\n data = _.clone(data, false);\n return this.http.post(url, data);\n };\n\n return AuthService;\n\n })(taiga.Service);\n\n module.service(\"$tgAuth\", AuthService);\n\n PublicRegisterMessageDirective = function($config, $navUrls, templates) {\n var template, templateFn;\n template = templates.get(\"auth/login-text.html\", true);\n templateFn = function() {\n var publicRegisterEnabled;\n publicRegisterEnabled = $config.get(\"publicRegisterEnabled\");\n if (!publicRegisterEnabled) {\n return \"\";\n }\n return template({\n url: $navUrls.resolve(\"register\")\n });\n };\n return {\n restrict: \"AE\",\n scope: {},\n template: templateFn\n };\n };\n\n module.directive(\"tgPublicRegisterMessage\", [\"$tgConfig\", \"$tgNavUrls\", \"$tgTemplate\", PublicRegisterMessageDirective]);\n\n LoginDirective = function($auth, $confirm, $location, $config, $routeParams, $navUrls, $events) {\n var link;\n link = function($scope, $el, $attrs) {\n var onError, onSuccess, submit;\n onSuccess = function(response) {\n var nextUrl;\n if ($routeParams['next'] && $routeParams['next'] !== $navUrls.resolve(\"login\")) {\n nextUrl = $routeParams['next'];\n } else {\n nextUrl = $navUrls.resolve(\"home\");\n }\n $events.setupConnection();\n return $location.path(nextUrl);\n };\n onError = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your username/email or password are incorrect.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, promise;\n event.preventDefault();\n form = new checksley.Form($el.find(\"form.login-form\"));\n if (!form.validate()) {\n return;\n }\n data = {\n \"username\": $el.find(\"form.login-form input[name=username]\").val(),\n \"password\": $el.find(\"form.login-form input[name=password]\").val()\n };\n promise = $auth.login(data);\n return promise.then(onSuccess, onError);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLogin\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgConfig\", \"$routeParams\", \"$tgNavUrls\", \"$tgEvents\", LoginDirective]);\n\n RegisterDirective = function($auth, $confirm, $location, $navUrls, $config, $analytics) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n if (!$config.get(\"publicRegisterEnabled\")) {\n $location.path($navUrls.resolve(\"not-found\"));\n $location.replace();\n }\n $scope.data = {};\n form = $el.find(\"form\").checksley({\n onlyOneErrorElement: true\n });\n onSuccessSubmit = function(response) {\n $analytics.trackEvent(\"auth\", \"register\", \"user registration\", 1);\n $confirm.notify(\"success\", \"Our Oompa Loompas are happy, welcome to Taiga.\");\n return $location.path($navUrls.resolve(\"home\"));\n };\n onErrorSubmit = function(response) {\n if (response.data._error_message != null) {\n $confirm.notify(\"light-error\", \"According to our Oompa Loompas there was an error. \" + response.data._error_message);\n }\n return form.setErrors(response.data);\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.register($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRegister\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfig\", \"$tgAnalytics\", RegisterDirective]);\n\n ForgotPasswordDirective = function($auth, $confirm, $location, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Check your inbox!
    We have sent a mail to
    \" + response.data.email + \"
    with the instructions to set a new password\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your are not registered yet.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.forgotPassword($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgForgotPassword\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$tgNavUrls\", ForgotPasswordDirective]);\n\n ChangePasswordFromRecoveryDirective = function($auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n if ($params.token != null) {\n $scope.tokenInParams = true;\n $scope.data.token = $params.token;\n } else {\n $scope.tokenInParams = false;\n }\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Our Oompa Loompas saved your new password.
    Try to sign in with it.\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"light-error\", \"One of our Oompa Loompas say '\" + response.data._error_message + \"'.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.changePasswordFromRecovery($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgChangePasswordFromRecovery\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", ChangePasswordFromRecoveryDirective]);\n\n InvitationDirective = function($auth, $confirm, $location, $params, $navUrls, $analytics) {\n var link;\n link = function($scope, $el, $attrs) {\n var loginForm, onErrorSubmitLogin, onErrorSubmitRegister, onSuccessSubmitLogin, onSuccessSubmitRegister, promise, registerForm, submitLogin, submitRegister, token;\n token = $params.token;\n promise = $auth.getInvitation(token);\n promise.then(function(invitation) {\n return $scope.invitation = invitation;\n });\n promise.then(null, function(response) {\n $location.path($navUrls.resolve(\"login\"));\n return $confirm.success(\"Ooops, we have a problem
    Our Oompa Loompas can't find your invitation.\");\n });\n $scope.dataLogin = {\n token: token\n };\n loginForm = $el.find(\"form.login-form\").checksley({\n onlyOneErrorElement: true\n });\n onSuccessSubmitLogin = function(response) {\n $analytics.trackEvent(\"auth\", \"invitationAccept\", \"invitation accept with existing user\", 1);\n $location.path($navUrls.resolve(\"project\", {\n project: $scope.invitation.project_slug\n }));\n return $confirm.notify(\"success\", \"You've successfully joined this project\", \"Welcome to \" + (_.escape($scope.invitation.project_name)));\n };\n onErrorSubmitLogin = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, your are not registered yet or typed an invalid password.\");\n };\n submitLogin = debounce(2000, (function(_this) {\n return function(event) {\n event.preventDefault();\n if (!loginForm.validate()) {\n return;\n }\n promise = $auth.acceptInvitiationWithExistingUser($scope.dataLogin);\n return promise.then(onSuccessSubmitLogin, onErrorSubmitLogin);\n };\n })(this));\n $el.on(\"submit\", \"form.login-form\", submitLogin);\n $el.on(\"click\", \".button-login\", submitLogin);\n $scope.dataRegister = {\n token: token\n };\n registerForm = $el.find(\"form.register-form\").checksley();\n onSuccessSubmitRegister = function(response) {\n $analytics.trackEvent(\"auth\", \"invitationAccept\", \"invitation accept with new user\", 1);\n $location.path($navUrls.resolve(\"project\", {\n project: $scope.invitation.project_slug\n }));\n return $confirm.notify(\"success\", \"You've successfully joined this project\", \"Welcome to \" + (_.escape($scope.invitation.project_name)));\n };\n onErrorSubmitRegister = function(response) {\n return $confirm.notify(\"light-error\", \"According to our Oompa Loompas, that username or email is already in use.\");\n };\n submitRegister = debounce(2000, (function(_this) {\n return function(event) {\n event.preventDefault();\n if (!registerForm.validate()) {\n return;\n }\n promise = $auth.acceptInvitiationWithNewUser($scope.dataRegister);\n return promise.then(onSuccessSubmitRegister, onErrorSubmitRegister);\n };\n })(this));\n $el.on(\"submit\", \"form.register-form\", submitRegister);\n return $el.on(\"click\", \".button-register\", submitRegister);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgInvitation\", [\"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", \"$tgAnalytics\", InvitationDirective]);\n\n ChangeEmailDirective = function($repo, $model, $auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n $scope.data.email_token = $params.email_token;\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n return $repo.queryOne(\"users\", $auth.getUser().id).then((function(_this) {\n return function(data) {\n $auth.setUser(data);\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.success(\"Our Oompa Loompas updated your email\");\n };\n })(this));\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"error\", \"One of our Oompa Loompas says '\" + response.data._error_message + \"'.\");\n };\n submit = function() {\n var promise;\n if (!form.validate()) {\n return;\n }\n promise = $auth.changeEmail($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n $el.on(\"submit\", function(event) {\n event.preventDefault();\n return submit();\n });\n return $el.on(\"click\", \"a.button-change-email\", function(event) {\n event.preventDefault();\n return submit();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgChangeEmail\", [\"$tgRepo\", \"$tgModel\", \"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", ChangeEmailDirective]);\n\n CancelAccountDirective = function($repo, $model, $auth, $confirm, $location, $params, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit;\n $scope.data = {};\n $scope.data.cancel_token = $params.cancel_token;\n form = $el.find(\"form\").checksley();\n onSuccessSubmit = function(response) {\n $auth.logout();\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.success(\"Our Oompa Loompas removed your account\");\n };\n onErrorSubmit = function(response) {\n return $confirm.notify(\"error\", \"One of our Oompa Loompas says '\" + response.data._error_message + \"'.\");\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n promise = $auth.cancelAccount($scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgCancelAccount\", [\"$tgRepo\", \"$tgModel\", \"$tgAuth\", \"$tgConfirm\", \"$tgLocation\", \"$routeParams\", \"$tgNavUrls\", CancelAccountDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaBacklog\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base.coffee\n */\n\n(function() {\n var TaigaMainDirective, bindOnce, groupBy, init, module, taiga, urls;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaBase\", [\"taigaLocales\"]);\n\n TaigaMainDirective = function($rootscope, $window) {\n var link;\n link = function($scope, $el, $attrs) {\n return $window.onresize = function() {\n return $rootscope.$broadcast(\"resize\");\n };\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMain\", [\"$rootScope\", \"$window\", TaigaMainDirective]);\n\n urls = {\n \"home\": \"/\",\n \"error\": \"/error\",\n \"not-found\": \"/not-found\",\n \"permission-denied\": \"/permission-denied\",\n \"login\": \"/login\",\n \"forgot-password\": \"/forgot-password\",\n \"change-password\": \"/change-password/:token\",\n \"change-email\": \"/change-email/:token\",\n \"cancel-account\": \"/cancel-account/:token\",\n \"register\": \"/register\",\n \"invitation\": \"/invitation/:token\",\n \"create-project\": \"/create-project\",\n \"profile\": \"/:user\",\n \"project\": \"/project/:project\",\n \"project-backlog\": \"/project/:project/backlog\",\n \"project-taskboard\": \"/project/:project/taskboard/:sprint\",\n \"project-kanban\": \"/project/:project/kanban\",\n \"project-issues\": \"/project/:project/issues\",\n \"project-search\": \"/project/:project/search\",\n \"project-userstories-detail\": \"/project/:project/us/:ref\",\n \"project-tasks-detail\": \"/project/:project/task/:ref\",\n \"project-issues-detail\": \"/project/:project/issue/:ref\",\n \"project-wiki\": \"/project/:project/wiki\",\n \"project-wiki-page\": \"/project/:project/wiki/:slug\",\n \"project-team\": \"/project/:project/team\",\n \"project-admin-home\": \"/project/:project/admin/project-profile/details\",\n \"project-admin-project-profile-details\": \"/project/:project/admin/project-profile/details\",\n \"project-admin-project-profile-default-values\": \"/project/:project/admin/project-profile/default-values\",\n \"project-admin-project-profile-modules\": \"/project/:project/admin/project-profile/modules\",\n \"project-admin-project-profile-export\": \"/project/:project/admin/project-profile/export\",\n \"project-admin-project-values-us-status\": \"/project/:project/admin/project-values/us-status\",\n \"project-admin-project-values-us-points\": \"/project/:project/admin/project-values/us-points\",\n \"project-admin-project-values-task-status\": \"/project/:project/admin/project-values/task-status\",\n \"project-admin-project-values-issue-status\": \"/project/:project/admin/project-values/issue-status\",\n \"project-admin-project-values-issue-types\": \"/project/:project/admin/project-values/issue-types\",\n \"project-admin-project-values-issue-priorities\": \"/project/:project/admin/project-values/issue-priorities\",\n \"project-admin-project-values-issue-severities\": \"/project/:project/admin/project-values/issue-severities\",\n \"project-admin-memberships\": \"/project/:project/admin/memberships\",\n \"project-admin-roles\": \"/project/:project/admin/roles\",\n \"project-admin-third-parties-webhooks\": \"/project/:project/admin/third-parties/webhooks\",\n \"project-admin-third-parties-github\": \"/project/:project/admin/third-parties/github\",\n \"project-admin-third-parties-gitlab\": \"/project/:project/admin/third-parties/gitlab\",\n \"project-admin-third-parties-bitbucket\": \"/project/:project/admin/third-parties/bitbucket\",\n \"project-admin-contrib\": \"/project/:project/admin/contrib/:plugin\",\n \"user-settings-user-profile\": \"/project/:project/user-settings/user-profile\",\n \"user-settings-user-change-password\": \"/project/:project/user-settings/user-change-password\",\n \"user-settings-user-avatar\": \"/project/:project/user-settings/user-avatar\",\n \"user-settings-mail-notifications\": \"/project/:project/user-settings/mail-notifications\"\n };\n\n init = function($log, $navurls) {\n $log.debug(\"Initialize navigation urls\");\n return $navurls.update(urls);\n };\n\n module.run([\"$log\", \"$tgNavUrls\", init]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common.coffee\n */\n\n(function() {\n var AnimationFrame, AppTitle, CheckPermissionDirective, LimitLineLengthDirective, ProjectUrl, Qqueue, SelectedText, Template, ToggleCommentDirective, module, taiga,\n __slice = [].slice;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\", []);\n\n SelectedText = function($window, $document) {\n var get;\n get = function() {\n if ($window.getSelection) {\n return $window.getSelection().toString();\n } else if ($document.selection) {\n return $document.selection.createRange().text;\n }\n return \"\";\n };\n return {\n get: get\n };\n };\n\n module.factory(\"$selectedText\", [\"$window\", \"$document\", SelectedText]);\n\n CheckPermissionDirective = function() {\n var link, render;\n render = function($el, project, permission) {\n if (project.my_permissions.indexOf(permission) > -1) {\n return $el.removeClass('hidden');\n }\n };\n link = function($scope, $el, $attrs) {\n var permission;\n $el.addClass('hidden');\n permission = $attrs.tgCheckPermission;\n $scope.$watch(\"project\", function(project) {\n if (project != null) {\n return render($el, project, permission);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgCheckPermission\", CheckPermissionDirective);\n\n AnimationFrame = function() {\n var add, animationFrame, performAnimation, tail;\n animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;\n performAnimation = (function(_this) {\n return function(time) {\n var fn;\n fn = tail.shift();\n fn();\n if (tail.length) {\n return animationFrame(performAnimation);\n }\n };\n })(this);\n tail = [];\n add = function() {\n var fn, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = arguments.length; _i < _len; _i++) {\n fn = arguments[_i];\n tail.push(fn);\n if (tail.length === 1) {\n _results.push(animationFrame(performAnimation));\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n };\n return {\n add: add\n };\n };\n\n module.factory(\"animationFrame\", AnimationFrame);\n\n ToggleCommentDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.find(\"textarea\").on(\"focus\", function() {\n return $el.addClass(\"active\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgToggleComment\", ToggleCommentDirective);\n\n AppTitle = function() {\n var set;\n set = function(text) {\n return $(\"title\").text(text);\n };\n return {\n set: set\n };\n };\n\n module.factory(\"$appTitle\", AppTitle);\n\n ProjectUrl = function($navurls) {\n var get;\n get = function(project) {\n var ctx;\n ctx = {\n project: project.slug\n };\n if (project.is_backlog_activated && project.my_permissions.indexOf(\"view_us\") > -1) {\n return $navurls.resolve(\"project-backlog\", ctx);\n }\n if (project.is_kanban_activated && project.my_permissions.indexOf(\"view_us\") > -1) {\n return $navurls.resolve(\"project-kanban\", ctx);\n }\n if (project.is_wiki_activated && project.my_permissions.indexOf(\"view_wiki_pages\") > -1) {\n return $navurls.resolve(\"project-wiki\", ctx);\n }\n if (project.is_issues_activated && project.my_permissions.indexOf(\"view_issues\") > -1) {\n return $navurls.resolve(\"project-issues\", ctx);\n }\n return $navurls.resolve(\"project\", ctx);\n };\n return {\n get: get\n };\n };\n\n module.factory(\"$projectUrl\", [\"$tgNavUrls\", ProjectUrl]);\n\n LimitLineLengthDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var maxColsPerLine;\n maxColsPerLine = parseInt($el.attr(\"cols\"));\n return $el.on(\"keyup\", function(event) {\n var code, lines;\n code = event.keyCode;\n lines = $el.val().split(\"\\n\");\n _.each(lines, function(line, index) {\n return lines[index] = line.substring(0, maxColsPerLine - 2);\n });\n return $el.val(lines.join(\"\\n\"));\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLimitLineLength\", LimitLineLengthDirective);\n\n Qqueue = function($q) {\n var deferred, lastPromise, qqueue;\n deferred = $q.defer();\n deferred.resolve();\n lastPromise = deferred.promise;\n qqueue = {\n bindAdd: (function(_this) {\n return function(fn) {\n return function() {\n var args;\n args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];\n return lastPromise = lastPromise.then(function() {\n return fn.apply(_this, args);\n });\n };\n return qqueue;\n };\n })(this),\n add: (function(_this) {\n return function(fn) {\n if (!lastPromise) {\n lastPromise = fn();\n } else {\n lastPromise = lastPromise.then(fn);\n }\n return qqueue;\n };\n })(this)\n };\n return qqueue;\n };\n\n module.factory(\"$tgQqueue\", [\"$q\", Qqueue]);\n\n Template = function($templateCache) {\n return {\n get: (function(_this) {\n return function(name, lodash) {\n var tmp;\n if (lodash == null) {\n lodash = false;\n }\n tmp = $templateCache.get(name);\n if (lodash) {\n tmp = _.template(tmp);\n }\n return tmp;\n };\n })(this)\n };\n };\n\n module.factory(\"$tgTemplate\", [\"$templateCache\", Template]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/events.coffee\n */\n\n(function() {\n var EventsProvider, EventsService, bindMethods, module, startswith, taiga;\n\n taiga = this.taiga;\n\n startswith = this.taiga.startswith;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaEvents\", []);\n\n EventsService = (function() {\n function EventsService(win, log, config, auth) {\n this.win = win;\n this.log = log;\n this.config = config;\n this.auth = auth;\n bindMethods(this);\n }\n\n EventsService.prototype.initialize = function(sessionId) {\n this.sessionId = sessionId;\n this.subscriptions = {};\n this.connected = false;\n this.error = false;\n this.pendingMessages = [];\n if (this.win.WebSocket === void 0) {\n return this.log.info(\"WebSockets not supported on your browser\");\n }\n };\n\n EventsService.prototype.setupConnection = function() {\n var loc, path, scheme, url;\n this.stopExistingConnection();\n url = this.config.get(\"eventsUrl\");\n if (!url) {\n return;\n }\n if (!startswith(url, \"ws:\") && !startswith(url, \"wss:\")) {\n loc = this.win.location;\n scheme = loc.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n path = _.str.ltrim(url, \"/\");\n url = \"\" + scheme + \"//\" + loc.host + \"/\" + path;\n }\n this.ws = new this.win.WebSocket(url);\n this.ws.addEventListener(\"open\", this.onOpen);\n this.ws.addEventListener(\"message\", this.onMessage);\n this.ws.addEventListener(\"error\", this.onError);\n return this.ws.addEventListener(\"close\", this.onClose);\n };\n\n EventsService.prototype.stopExistingConnection = function() {\n if (this.ws === void 0) {\n return;\n }\n this.ws.removeEventListener(\"open\", this.onOpen);\n this.ws.removeEventListener(\"close\", this.onClose);\n this.ws.removeEventListener(\"error\", this.onError);\n this.ws.removeEventListener(\"message\", this.onMessage);\n this.ws.close();\n return delete this.ws;\n };\n\n EventsService.prototype.serialize = function(message) {\n if (_.isObject(message)) {\n return JSON.stringify(message);\n }\n return message;\n };\n\n EventsService.prototype.sendMessage = function(message) {\n var messages, msg, _i, _len, _results;\n this.pendingMessages.push(message);\n if (!this.connected) {\n return;\n }\n messages = _.map(this.pendingMessages, this.serialize);\n this.pendingMessages = [];\n _results = [];\n for (_i = 0, _len = messages.length; _i < _len; _i++) {\n msg = messages[_i];\n _results.push(this.ws.send(msg));\n }\n return _results;\n };\n\n EventsService.prototype.subscribe = function(scope, routingKey, callback) {\n var message, subscription;\n if (this.error) {\n return;\n }\n this.log.debug(\"Subscribe to: \" + routingKey);\n subscription = {\n scope: scope,\n routingKey: routingKey,\n callback: _.debounce(callback, 500, {\n \"leading\": true,\n \"trailing\": false\n })\n };\n message = {\n \"cmd\": \"subscribe\",\n \"routing_key\": routingKey\n };\n this.subscriptions[routingKey] = subscription;\n this.sendMessage(message);\n return scope.$on(\"$destroy\", (function(_this) {\n return function() {\n return _this.unsubscribe(routingKey);\n };\n })(this));\n };\n\n EventsService.prototype.unsubscribe = function(routingKey) {\n var message;\n if (this.error) {\n return;\n }\n this.log.debug(\"Unsubscribe from: \" + routingKey);\n message = {\n \"cmd\": \"unsubscribe\",\n \"routing_key\": routingKey\n };\n return this.sendMessage(message);\n };\n\n EventsService.prototype.onOpen = function() {\n var message, token;\n this.connected = true;\n this.log.debug(\"WebSocket connection opened\");\n token = this.auth.getToken();\n message = {\n cmd: \"auth\",\n data: {\n token: token,\n sessionId: this.sessionId\n }\n };\n return this.sendMessage(message);\n };\n\n EventsService.prototype.onMessage = function(event) {\n var data, routingKey, subscription;\n this.log.debug(\"WebSocket message received: \" + event.data);\n data = JSON.parse(event.data);\n routingKey = data.routing_key;\n if (this.subscriptions[routingKey] == null) {\n return;\n }\n subscription = this.subscriptions[routingKey];\n return subscription.scope.$apply(function() {\n return subscription.callback(data.data);\n });\n };\n\n EventsService.prototype.onError = function(error) {\n this.log.error(\"WebSocket error: \" + error);\n return this.error = true;\n };\n\n EventsService.prototype.onClose = function() {\n this.log.debug(\"WebSocket closed.\");\n return this.connected = false;\n };\n\n return EventsService;\n\n })();\n\n EventsProvider = (function() {\n function EventsProvider() {}\n\n EventsProvider.prototype.setSessionId = function(sessionId) {\n return this.sessionId = sessionId;\n };\n\n EventsProvider.prototype.$get = function($win, $log, $conf, $auth) {\n var service;\n service = new EventsService($win, $log, $conf, $auth);\n service.initialize(this.sessionId);\n return service;\n };\n\n EventsProvider.prototype.$get.$inject = [\"$window\", \"$log\", \"$tgConfig\", \"$tgAuth\"];\n\n return EventsProvider;\n\n })();\n\n module.provider(\"$tgEvents\", EventsProvider);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/feedback.coffee\n */\n\n(function() {\n var FeedbackDirective, bindOnce, debounce, groupBy, mixOf, module, taiga, trim;\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n mixOf = this.taiga.mixOf;\n\n debounce = this.taiga.debounce;\n\n trim = this.taiga.trim;\n\n module = angular.module(\"taigaFeedback\", []);\n\n FeedbackDirective = function($lightboxService, $repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley();\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"feedback\", $scope.feedback);\n promise.then(function(data) {\n $loading.finish(submitButton);\n $lightboxService.close($el);\n return $confirm.notify(\"success\", \"\\\\o/ we'll be happy to read your\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $scope.$on(\"feedback:show\", function() {\n $scope.$apply(function() {\n return $scope.feedback = {};\n });\n $lightboxService.open($el);\n return $el.find(\"textarea\").focus();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbFeedback\", [\"lightboxService\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", FeedbackDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/integrations.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaIntegrations\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaIssues\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaKanban\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/locales.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaLocales\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/nav.coffee\n */\n\n(function() {\n var ProjectMenuDirective, ProjectsNavigationController, ProjectsNavigationDirective, bindOnce, groupBy, module, taiga, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaNavMenu\", []);\n\n ProjectsNavigationController = (function(_super) {\n __extends(ProjectsNavigationController, _super);\n\n ProjectsNavigationController.$inject = [\"$scope\", \"$rootScope\", \"$tgResources\", \"$tgNavUrls\", \"$projectUrl\"];\n\n function ProjectsNavigationController(scope, rootscope, rs, navurls, projectUrl) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.rs = rs;\n this.navurls = navurls;\n this.projectUrl = projectUrl;\n promise = this.loadInitialData();\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n this.scope.$on(\"projects:reload\", (function(_this) {\n return function() {\n return _this.loadInitialData();\n };\n })(this));\n this.scope.$on(\"project:loaded\", (function(_this) {\n return function(ctx, project) {\n return _this.loadInitialData();\n };\n })(this));\n }\n\n ProjectsNavigationController.prototype.loadInitialData = function() {\n return this.rs.projects.list().then((function(_this) {\n return function(projects) {\n var project, _i, _len;\n for (_i = 0, _len = projects.length; _i < _len; _i++) {\n project = projects[_i];\n project.url = _this.projectUrl.get(project);\n }\n _this.scope.projects = projects;\n _this.scope.filteredProjects = projects;\n _this.scope.filterText = \"\";\n return projects;\n };\n })(this));\n };\n\n ProjectsNavigationController.prototype.newProject = function() {\n return this.scope.$apply((function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"projects:create\");\n };\n })(this));\n };\n\n ProjectsNavigationController.prototype.filterProjects = function(text) {\n this.scope.filteredProjects = _.filter(this.scope.projects, function(project) {\n return project.name.toLowerCase().indexOf(text) > -1;\n });\n this.scope.filterText = text;\n return this.rootscope.$broadcast(\"projects:filtered\");\n };\n\n return ProjectsNavigationController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectsNavigationController\", ProjectsNavigationController);\n\n ProjectsNavigationDirective = function($rootscope, animationFrame, $timeout, tgLoader, $location, $compile, $template) {\n var baseTemplate, hideMenu, link, loadingStart, overlay, projectsTemplate;\n baseTemplate = $template.get(\"project/project-navigation-base.html\", true);\n projectsTemplate = $template.get(\"project/project-navigation-list.html\", true);\n overlay = $(\".projects-nav-overlay\");\n loadingStart = 0;\n hideMenu = function() {\n var difftime, timeoutValue;\n if (overlay.is(':visible')) {\n difftime = new Date().getTime() - loadingStart;\n timeoutValue = 0;\n if (difftime < 1000) {\n timeoutValue = 1000 - timeoutValue;\n }\n return timeout(timeoutValue, function() {\n overlay.one('transitionend', function() {\n $(document.body).removeClass(\"loading-project open-projects-nav closed-projects-nav\").css(\"overflow-x\", \"visible\");\n return overlay.hide();\n });\n $(document.body).addClass(\"closed-projects-nav\");\n return tgLoader.disablePreventLoading();\n });\n }\n };\n link = function($scope, $el, $attrs, $ctrls) {\n var $ctrl, render, renderProjects;\n $ctrl = $ctrls[0];\n $rootscope.$on(\"project:loaded\", hideMenu);\n renderProjects = function(projects) {\n var html;\n html = projectsTemplate({\n projects: projects\n });\n $el.find(\".projects-list\").html(html);\n return $scope.$emit(\"regenerate:project-pagination\");\n };\n render = function(projects) {\n $el.html($compile(baseTemplate())($scope));\n return renderProjects(projects);\n };\n overlay.on('click', function() {\n return hideMenu();\n });\n $(document).on('keydown', (function(_this) {\n return function(e) {\n var code;\n code = e.keyCode ? e.keyCode : e.which;\n if (code === 27) {\n return hideMenu();\n }\n };\n })(this));\n $scope.$on(\"nav:projects-list:open\", function() {\n if (!$(document.body).hasClass(\"open-projects-nav\")) {\n animationFrame.add((function(_this) {\n return function() {\n return overlay.show();\n };\n })(this));\n }\n return animationFrame.add((function(_this) {\n return function() {\n return $(document.body).css(\"overflow-x\", \"hidden\");\n };\n })(this), (function(_this) {\n return function() {\n return $(document.body).toggleClass(\"open-projects-nav\");\n };\n })(this));\n });\n $el.on(\"click\", \".projects-list > li > a\", function(event) {\n var currentUrl, nextUrl, target;\n target = angular.element(event.currentTarget);\n nextUrl = target.prop(\"href\");\n currentUrl = $location.absUrl();\n if (nextUrl === currentUrl) {\n hideMenu();\n return;\n }\n $(document.body).addClass('loading-project');\n tgLoader.preventLoading();\n return loadingStart = new Date().getTime();\n });\n $el.on(\"click\", \".create-project-button\", function(event) {\n event.preventDefault();\n return $ctrl.newProject();\n });\n $el.on(\"keyup\", \".search-project\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n return $ctrl.filterProjects(target.val());\n });\n $scope.$on(\"projects:filtered\", function() {\n return renderProjects($scope.filteredProjects);\n });\n return $scope.$watch(\"projects\", function(projects) {\n if (projects != null) {\n return render(projects);\n }\n });\n };\n return {\n require: [\"tgProjectsNav\"],\n controller: ProjectsNavigationController,\n link: link\n };\n };\n\n module.directive(\"tgProjectsNav\", [\"$rootScope\", \"animationFrame\", \"$timeout\", \"tgLoader\", \"$tgLocation\", \"$compile\", \"$tgTemplate\", ProjectsNavigationDirective]);\n\n ProjectMenuDirective = function($log, $compile, $auth, $rootscope, $tgAuth, $location, $navUrls, $config, $template) {\n var getSectionName, link, mainTemplate, menuEntriesTemplate, renderMainMenu, renderMenuEntries, videoConferenceUrl;\n menuEntriesTemplate = $template.get(\"project/project-menu.html\", true);\n mainTemplate = _.template(\"
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n taiga[beta]\\n
    \\n
    \");\n getSectionName = function($el, sectionName, project) {\n var oldSectionName, _ref;\n oldSectionName = (_ref = $el.find(\"a.active\").parent().attr(\"id\")) != null ? _ref.replace(\"nav-\", \"\") : void 0;\n if (sectionName === \"backlog-kanban\") {\n if (oldSectionName === \"backlog\" || oldSectionName === \"kanban\") {\n sectionName = oldSectionName;\n } else if (project.is_backlog_activated && !project.is_kanban_activated) {\n sectionName = \"backlog\";\n } else if (!project.is_backlog_activated && project.is_kanban_activated) {\n sectionName = \"kanban\";\n }\n }\n return sectionName;\n };\n renderMainMenu = function($el) {\n var html;\n html = mainTemplate({});\n return $el.html(html);\n };\n renderMenuEntries = function($el, targetScope, project) {\n var container, ctx, dom, sectionName;\n if (project == null) {\n project = {};\n }\n container = $el.find(\".menu-container\");\n sectionName = getSectionName($el, targetScope.section, project);\n ctx = {\n user: $auth.getUser(),\n project: project,\n feedbackEnabled: $config.get(\"feedbackEnabled\")\n };\n dom = $compile(menuEntriesTemplate(ctx))(targetScope);\n dom.find(\"a.active\").removeClass(\"active\");\n dom.find(\"#nav-\" + sectionName + \" > a\").addClass(\"active\");\n return container.replaceWith(dom);\n };\n videoConferenceUrl = function(project) {\n var baseUrl, url;\n if (project.videoconferences === \"appear-in\") {\n baseUrl = \"https://appear.in/\";\n } else if (project.videoconferences === \"talky\") {\n baseUrl = \"https://talky.io/\";\n } else {\n return \"\";\n }\n if (project.videoconferences_salt) {\n url = \"\" + project.slug + \"-\" + project.videoconferences_salt;\n } else {\n url = \"\" + project.slug;\n }\n return baseUrl + url;\n };\n link = function($scope, $el, $attrs, $ctrl) {\n var project;\n renderMainMenu($el);\n project = null;\n $el.on(\"click\", \".logo\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return $rootscope.$broadcast(\"nav:projects-list:open\");\n });\n $el.on(\"click\", \".user-settings .avatar\", function(event) {\n event.preventDefault();\n return $el.find(\".user-settings .popover\").popover().open();\n });\n $el.on(\"click\", \".logout\", function(event) {\n event.preventDefault();\n $auth.logout();\n return $scope.$apply(function() {\n return $location.path($navUrls.resolve(\"login\"));\n });\n });\n $el.on(\"click\", \"#nav-search > a\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"search-box:show\", project);\n });\n $el.on(\"click\", \".feedback\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"feedback:show\");\n });\n $scope.$on(\"projects:loaded\", function(listener) {\n $el.addClass(\"hidden\");\n return listener.stopPropagation();\n });\n return $scope.$on(\"project:loaded\", function(ctx, newProject) {\n project = newProject;\n if ($el.hasClass(\"hidden\")) {\n $el.removeClass(\"hidden\");\n }\n project.videoconferenceUrl = videoConferenceUrl(project);\n return renderMenuEntries($el, ctx.targetScope, project);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectMenu\", [\"$log\", \"$compile\", \"$tgAuth\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfig\", \"$tgTemplate\", ProjectMenuDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/projects.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaProject\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/related-tasks.coffee\n */\n\n(function() {\n var RelatedTaskAssignedToInlineEditionDirective, RelatedTaskCreateButtonDirective, RelatedTaskCreateFormDirective, RelatedTaskRowDirective, RelatedTasksDirective, debounce, module, taiga, trim;\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaRelatedTasks\", []);\n\n RelatedTaskRowDirective = function($repo, $compile, $confirm, $rootscope, $loading, $template) {\n var link, templateEdit, templateView;\n templateView = $template.get(\"task/related-task-row.html\", true);\n templateEdit = $template.get(\"task/related-task-row-edit.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var renderEdit, renderView, saveTask;\n saveTask = debounce(2000, function(task) {\n var promise;\n task.subject = $el.find('input').val();\n $loading.start($el.find('.task-name'));\n promise = $repo.save(task);\n promise.then((function(_this) {\n return function() {\n $loading.finish($el.find('.task-name'));\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"related-tasks:update\");\n };\n })(this));\n promise.then(null, (function(_this) {\n return function() {\n $loading.finish($el.find('.task-name'));\n $el.find('input').val(task.subject);\n return $confirm.notify(\"error\");\n };\n })(this));\n return promise;\n });\n renderEdit = function(task) {\n $el.html($compile(templateEdit({\n task: task\n }))($scope));\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return saveTask($model.$modelValue).then(function() {\n return renderView($model.$modelValue);\n });\n } else if (event.keyCode === 27) {\n return renderView($model.$modelValue);\n }\n });\n $el.on(\"click\", \".icon-floppy\", function(event) {\n return saveTask($model.$modelValue).then(function() {\n return renderView($model.$modelValue);\n });\n });\n return $el.on(\"click\", \".cancel-edit\", function(event) {\n return renderView($model.$modelValue);\n });\n };\n renderView = function(task) {\n var perms;\n $el.off();\n perms = {\n modify_task: $scope.project.my_permissions.indexOf(\"modify_task\") !== -1,\n delete_task: $scope.project.my_permissions.indexOf(\"delete_task\") !== -1\n };\n $el.html($compile(templateView({\n task: task,\n perms: perms\n }))($scope));\n $el.on(\"click\", \".icon-edit\", function() {\n renderEdit($model.$modelValue);\n return $el.find('input').focus().select();\n });\n return $el.on(\"click\", \".delete-task\", function(event) {\n var message, title;\n task = $model.$modelValue;\n title = \"Delete Task\";\n message = task.subject;\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var promise;\n promise = $repo.remove(task);\n promise.then(function() {\n finish();\n $confirm.notify(\"success\");\n return $scope.$emit(\"related-tasks:delete\");\n });\n return promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n });\n });\n };\n $scope.$watch($attrs.ngModel, function(val) {\n if (!val) {\n return;\n }\n return renderView(val);\n });\n $scope.$on(\"related-tasks:assigned-to-changed\", function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n $scope.$on(\"related-tasks:status-changed\", function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgRelatedTaskRow\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$rootScope\", \"$tgLoading\", \"$tgTemplate\", RelatedTaskRowDirective]);\n\n RelatedTaskCreateFormDirective = function($repo, $compile, $confirm, $tgmodel, $loading, $analytics, $template) {\n var link, newTask, template;\n template = $template.get(\"task/related-task-create-form.html\", true);\n newTask = {\n subject: \"\",\n assigned_to: null\n };\n link = function($scope, $el, $attrs) {\n var createTask, render;\n createTask = debounce(2000, function(task) {\n var promise;\n task.subject = $el.find('input').val();\n task.assigned_to = $scope.newTask.assigned_to;\n task.status = $scope.newTask.status;\n $scope.newTask.status = $scope.project.default_task_status;\n $scope.newTask.assigned_to = null;\n $loading.start($el.find('.task-name'));\n promise = $repo.create(\"tasks\", task);\n promise.then(function() {\n $analytics.trackEvent(\"task\", \"create\", \"create task on userstory\", 1);\n $loading.finish($el.find('.task-name'));\n $scope.$emit(\"related-tasks:add\");\n return $confirm.notify(\"success\");\n });\n promise.then(null, function() {\n $el.find('input').val(task.subject);\n $loading.finish($el.find('.task-name'));\n return $confirm.notify(\"error\");\n });\n return promise;\n });\n render = function() {\n $el.off();\n $el.html($compile(template())($scope));\n $el.find('input').focus().select();\n $el.addClass('active');\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return createTask(newTask).then(function() {\n return render();\n });\n } else if (event.keyCode === 27) {\n return $el.html(\"\");\n }\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n return $el.html(\"\");\n });\n return $el.on(\"click\", \".icon-floppy\", function(event) {\n return createTask(newTask).then(function() {\n return $el.html(\"\");\n });\n });\n };\n taiga.bindOnce($scope, \"us\", function(val) {\n newTask[\"status\"] = $scope.project.default_task_status;\n newTask[\"project\"] = $scope.project.id;\n newTask[\"user_story\"] = $scope.us.id;\n $scope.newTask = $tgmodel.make_model(\"tasks\", newTask);\n return $el.html(\"\");\n });\n $scope.$on(\"related-tasks:show-form\", function() {\n return render();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskCreateForm\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$tgModel\", \"$tgLoading\", \"$tgAnalytics\", \"$tgTemplate\", RelatedTaskCreateFormDirective]);\n\n RelatedTaskCreateButtonDirective = function($repo, $compile, $confirm, $tgmodel) {\n var link, template;\n template = _.template(\"\");\n link = function($scope, $el, $attrs) {\n $scope.$watch(\"project\", function(val) {\n if (!val) {\n return;\n }\n $el.off();\n if ($scope.project.my_permissions.indexOf(\"add_task\") !== -1) {\n $el.html(template());\n } else {\n $el.html(\"\");\n }\n return $el.on(\"click\", \".icon\", function(event) {\n return $scope.$emit(\"related-tasks:add-new-clicked\");\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskCreateButton\", [\"$tgRepo\", \"$compile\", \"$tgConfirm\", \"$tgModel\", RelatedTaskCreateButtonDirective]);\n\n RelatedTasksDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var loadTasks;\n loadTasks = function() {\n return $rs.tasks.list($scope.projectId, null, $scope.usId).then((function(_this) {\n return function(tasks) {\n $scope.tasks = tasks;\n return tasks;\n };\n })(this));\n };\n $scope.$on(\"related-tasks:add\", function() {\n return loadTasks().then(function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n });\n $scope.$on(\"related-tasks:delete\", function() {\n return loadTasks().then(function() {\n return $rootscope.$broadcast(\"related-tasks:update\");\n });\n });\n $scope.$on(\"related-tasks:add-new-clicked\", function() {\n return $scope.$broadcast(\"related-tasks:show-form\");\n });\n taiga.bindOnce($scope, \"us\", function(val) {\n return loadTasks();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTasks\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", RelatedTasksDirective]);\n\n RelatedTaskAssignedToInlineEditionDirective = function($repo, $rootscope, popoverService) {\n var link, template;\n template = _.template(\"\\\" alt=\\\"<%- name %>\\\"/>\\n
    <%- name %>
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, autoSave, notAutoSave, task, updateRelatedTask;\n updateRelatedTask = function(task) {\n var ctx, member;\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = $scope.usersById[task.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name_display;\n }\n $el.find(\".avatar\").html(template(ctx));\n return $el.find(\".task-assignedto\").attr('title', ctx.name);\n };\n $ctrl = $el.controller();\n task = $scope.$eval($attrs.tgRelatedTaskAssignedToInlineEdition);\n notAutoSave = $scope.$eval($attrs.notAutoSave);\n autoSave = !notAutoSave;\n updateRelatedTask(task);\n $el.on(\"click\", \".task-assignedto\", function(event) {\n return $rootscope.$broadcast(\"assigned-to:add\", task);\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_task\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"assigned-to:added\", debounce(2000, (function(_this) {\n return function(ctx, userId, updatedRelatedTask) {\n if (updatedRelatedTask.id === task.id) {\n updatedRelatedTask.assigned_to = userId;\n if (autoSave) {\n $repo.save(updatedRelatedTask).then(function() {\n return $scope.$emit(\"related-tasks:assigned-to-changed\");\n });\n }\n return updateRelatedTask(updatedRelatedTask);\n }\n };\n })(this)));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskAssignedToInlineEdition\", [\"$tgRepo\", \"$rootScope\", RelatedTaskAssignedToInlineEditionDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources.coffee\n */\n\n(function() {\n var ResourcesService, initResources, initUrls, module, taiga, urls,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n ResourcesService = (function(_super) {\n __extends(ResourcesService, _super);\n\n function ResourcesService() {\n return ResourcesService.__super__.constructor.apply(this, arguments);\n }\n\n return ResourcesService;\n\n })(taiga.Service);\n\n urls = {\n \"auth\": \"/auth\",\n \"auth-register\": \"/auth/register\",\n \"invitations\": \"/invitations\",\n \"permissions\": \"/permissions\",\n \"roles\": \"/roles\",\n \"projects\": \"/projects\",\n \"memberships\": \"/memberships\",\n \"notify-policies\": \"/notify-policies\",\n \"bulk-create-memberships\": \"/memberships/bulk_create\",\n \"milestones\": \"/milestones\",\n \"userstories\": \"/userstories\",\n \"bulk-create-us\": \"/userstories/bulk_create\",\n \"bulk-update-us-backlog-order\": \"/userstories/bulk_update_backlog_order\",\n \"bulk-update-us-sprint-order\": \"/userstories/bulk_update_sprint_order\",\n \"bulk-update-us-kanban-order\": \"/userstories/bulk_update_kanban_order\",\n \"userstories-restore\": \"/userstories/%s/restore\",\n \"tasks\": \"/tasks\",\n \"bulk-create-tasks\": \"/tasks/bulk_create\",\n \"bulk-update-task-taskboard-order\": \"/tasks/bulk_update_taskboard_order\",\n \"tasks-restore\": \"/tasks/%s/restore\",\n \"issues\": \"/issues\",\n \"bulk-create-issues\": \"/issues/bulk_create\",\n \"issues-restore\": \"/issues/%s/restore\",\n \"wiki\": \"/wiki\",\n \"wiki-restore\": \"/wiki/%s/restore\",\n \"wiki-links\": \"/wiki-links\",\n \"choices/userstory-statuses\": \"/userstory-statuses\",\n \"choices/userstory-statuses/bulk-update-order\": \"/userstory-statuses/bulk_update_order\",\n \"choices/points\": \"/points\",\n \"choices/points/bulk-update-order\": \"/points/bulk_update_order\",\n \"choices/task-statuses\": \"/task-statuses\",\n \"choices/task-statuses/bulk-update-order\": \"/task-statuses/bulk_update_order\",\n \"choices/issue-statuses\": \"/issue-statuses\",\n \"choices/issue-statuses/bulk-update-order\": \"/issue-statuses/bulk_update_order\",\n \"choices/issue-types\": \"/issue-types\",\n \"choices/issue-types/bulk-update-order\": \"/issue-types/bulk_update_order\",\n \"choices/priorities\": \"/priorities\",\n \"choices/priorities/bulk-update-order\": \"/priorities/bulk_update_order\",\n \"choices/severities\": \"/severities\",\n \"choices/severities/bulk-update-order\": \"/severities/bulk_update_order\",\n \"search\": \"/search\",\n \"sites\": \"/sites\",\n \"project-templates\": \"/project-templates\",\n \"site-members\": \"/site-members\",\n \"site-projects\": \"/site-projects\",\n \"users\": \"/users\",\n \"users-password-recovery\": \"/users/password_recovery\",\n \"users-change-password-from-recovery\": \"/users/change_password_from_recovery\",\n \"users-change-password\": \"/users/change_password\",\n \"users-change-email\": \"/users/change_email\",\n \"users-cancel-account\": \"/users/cancel\",\n \"user-storage\": \"/user-storage\",\n \"resolver\": \"/resolver\",\n \"userstory-statuses\": \"/userstory-statuses\",\n \"points\": \"/points\",\n \"task-statuses\": \"/task-statuses\",\n \"issue-statuses\": \"/issue-statuses\",\n \"issue-types\": \"/issue-types\",\n \"priorities\": \"/priorities\",\n \"severities\": \"/severities\",\n \"project-modules\": \"/projects/%s/modules\",\n \"webhooks\": \"/webhooks\",\n \"webhooks-test\": \"/webhooks/%s/test\",\n \"webhooklogs\": \"/webhooklogs\",\n \"webhooklogs-resend\": \"/webhooklogs/%s/resend\",\n \"history/us\": \"/history/userstory\",\n \"history/issue\": \"/history/issue\",\n \"history/task\": \"/history/task\",\n \"history/wiki\": \"/history/wiki\",\n \"attachments/us\": \"/userstories/attachments\",\n \"attachments/issue\": \"/issues/attachments\",\n \"attachments/task\": \"/tasks/attachments\",\n \"attachments/wiki_page\": \"/wiki/attachments\",\n \"feedback\": \"/feedback\",\n \"exporter\": \"/exporter\",\n \"importer\": \"/importer/load_dump\"\n };\n\n initUrls = function($log, $urls) {\n $log.debug(\"Initialize api urls\");\n return $urls.update(urls);\n };\n\n initResources = function($log, $rs) {\n var provider, providers, _i, _len, _results;\n $log.debug(\"Initialize resources\");\n providers = _.toArray(arguments).slice(2);\n _results = [];\n for (_i = 0, _len = providers.length; _i < _len; _i++) {\n provider = providers[_i];\n _results.push(provider($rs));\n }\n return _results;\n };\n\n module = angular.module(\"taigaResources\", [\"taigaBase\"]);\n\n module.service(\"$tgResources\", ResourcesService);\n\n module.run([\"$log\", \"$tgUrls\", initUrls]);\n\n module.run([\"$log\", \"$tgResources\", \"$tgProjectsResourcesProvider\", \"$tgMembershipsResourcesProvider\", \"$tgNotifyPoliciesResourcesProvider\", \"$tgInvitationsResourcesProvider\", \"$tgRolesResourcesProvider\", \"$tgUserSettingsResourcesProvider\", \"$tgSprintsResourcesProvider\", \"$tgUserstoriesResourcesProvider\", \"$tgTasksResourcesProvider\", \"$tgIssuesResourcesProvider\", \"$tgWikiResourcesProvider\", \"$tgSearchResourcesProvider\", \"$tgAttachmentsResourcesProvider\", \"$tgMdRenderResourcesProvider\", \"$tgHistoryResourcesProvider\", \"$tgKanbanResourcesProvider\", \"$tgModulesResourcesProvider\", \"$tgWebhooksResourcesProvider\", \"$tgWebhookLogsResourcesProvider\", initResources]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/search.coffee\n */\n\n(function() {\n var SearchBoxDirective, SearchController, SearchDirective, bindOnce, debounce, debounceLeading, groupBy, mixOf, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n mixOf = this.taiga.mixOf;\n\n debounceLeading = this.taiga.debounceLeading;\n\n trim = this.taiga.trim;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaSearch\", []);\n\n SearchController = (function(_super) {\n __extends(SearchController, _super);\n\n SearchController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"tgLoader\"];\n\n function SearchController(scope, repo, rs, params, q, location, appTitle, navUrls, tgLoader) {\n var loadSearchData, promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.tgLoader = tgLoader;\n this.scope.sectionName = \"Search\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Search\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.searchTerm = \"\";\n loadSearchData = debounceLeading(100, (function(_this) {\n return function(t) {\n return _this.loadSearchData(t);\n };\n })(this));\n this.scope.$watch(\"searchTerm\", (function(_this) {\n return function(term) {\n if (!term) {\n return _this.tgLoader.pageLoaded();\n } else {\n return loadSearchData(term);\n }\n };\n })(this));\n }\n\n SearchController.prototype.loadFilters = function() {\n var defered;\n defered = this.q.defer();\n defered.resolve();\n return defered.promise;\n };\n\n SearchController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issueStatusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.taskStatusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n return project;\n };\n })(this));\n };\n\n SearchController.prototype.loadSearchData = function(term) {\n var promise;\n promise = this.rs.search[\"do\"](this.scope.projectId, term).then((function(_this) {\n return function(data) {\n _this.scope.searchResults = data;\n return data;\n };\n })(this));\n promise[\"finally\"]((function(_this) {\n return function() {\n return _this.tgLoader.pageLoaded();\n };\n })(this));\n return promise;\n };\n\n SearchController.prototype.loadInitialData = function() {\n return this.loadProject().then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n return _this.fillUsersAndRoles(project.users, project.roles);\n };\n })(this));\n };\n\n return SearchController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"SearchController\", SearchController);\n\n SearchBoxDirective = function($lightboxService, $navurls, $location, $route) {\n var link;\n link = function($scope, $el, $attrs) {\n var project, submit;\n project = null;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, text, url;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n text = $el.find(\"#search-text\").val();\n url = $navurls.resolve(\"project-search\", {\n project: project.slug\n });\n $lightboxService.close($el);\n return $scope.$apply(function() {\n $location.path(url);\n $location.search(\"text\", text).path(url);\n return $route.reload();\n });\n };\n })(this));\n $scope.$on(\"search-box:show\", function(ctx, newProject) {\n project = newProject;\n $lightboxService.open($el);\n return $el.find(\"#search-text\").val(\"\");\n });\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSearchBox\", [\"lightboxService\", \"$tgNavUrls\", \"$tgLocation\", \"$route\", SearchBoxDirective]);\n\n SearchDirective = function($log, $compile, $templatecache, $routeparams, $location) {\n var link, linkTable;\n linkTable = function($scope, $el, $attrs, $ctrl) {\n var getActiveSection, lastSeatchResults, markSectionTabActive, renderFilterTabs, renderTableContent, tabsDom, templates;\n tabsDom = $el.find(\"section.search-filter\");\n lastSeatchResults = null;\n getActiveSection = function(data) {\n var maxVal, name, selectedSectionData, selectedSectionName, value;\n maxVal = 0;\n selectedSectionName = null;\n selectedSectionData = null;\n for (name in data) {\n value = data[name];\n if (name === \"count\") {\n continue;\n }\n if (value.length > maxVal) {\n maxVal = value.length;\n selectedSectionName = name;\n selectedSectionData = value;\n }\n }\n if (maxVal === 0) {\n return {\n name: \"userstories\",\n value: []\n };\n }\n return {\n name: selectedSectionName,\n value: selectedSectionData\n };\n };\n renderFilterTabs = function(data) {\n var name, value, _results;\n _results = [];\n for (name in data) {\n value = data[name];\n if (name === \"count\") {\n continue;\n }\n _results.push(tabsDom.find(\"li.\" + name + \" .num\").html(value.length));\n }\n return _results;\n };\n markSectionTabActive = function(section) {\n tabsDom.find(\"a.active\").removeClass(\"active\");\n return tabsDom.find(\"li.\" + section.name + \" a\").addClass(\"active\");\n };\n templates = {\n issues: $templatecache.get(\"search-issues\"),\n tasks: $templatecache.get(\"search-tasks\"),\n userstories: $templatecache.get(\"search-userstories\"),\n wikipages: $templatecache.get(\"search-wikipages\")\n };\n renderTableContent = function(section) {\n var element, oldElements, oldScope, scope, template;\n oldElements = $el.find(\".search-result-table\").children();\n oldScope = oldElements.scope();\n if (oldScope) {\n oldScope.$destroy();\n oldElements.remove();\n }\n scope = $scope.$new();\n scope[section.name] = section.value;\n template = angular.element.parseHTML(trim(templates[section.name]));\n element = $compile(template)(scope);\n return $el.find(\".search-result-table\").html(element);\n };\n $scope.$watch(\"searchResults\", function(data) {\n var activeSection;\n lastSeatchResults = data;\n activeSection = getActiveSection(data);\n renderFilterTabs(data);\n renderTableContent(activeSection);\n return markSectionTabActive(activeSection);\n });\n $scope.$watch(\"searchTerm\", function(searchTerm) {\n if (searchTerm) {\n return $location.search(\"text\", searchTerm);\n }\n });\n return $el.on(\"click\", \".search-filter li > a\", function(event) {\n var section, sectionData, sectionName, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n sectionName = target.parent().data(\"name\");\n sectionData = lastSeatchResults[sectionName];\n section = {\n name: sectionName,\n value: sectionData\n };\n return $scope.$apply(function() {\n renderTableContent(section);\n return markSectionTabActive(section);\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, searchText;\n $ctrl = $el.controller();\n linkTable($scope, $el, $attrs, $ctrl);\n searchText = $routeparams.text;\n return $scope.$watch(\"projectId\", function(projectId) {\n if (projectId != null) {\n return $scope.searchTerm = searchText;\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSearch\", [\"$log\", \"$compile\", \"$templateCache\", \"$routeParams\", \"$tgLocation\", SearchDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTaskboard\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/tasks.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTasks\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/team.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaTeam\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaUserSettings\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/userstories.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaUserStories\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaWiki\", []);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/analytics.coffee\n */\n\n(function() {\n var AnalyticsService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n AnalyticsService = (function(_super) {\n __extends(AnalyticsService, _super);\n\n AnalyticsService.$inject = [\"$rootScope\", \"$log\", \"$tgConfig\", \"$window\", \"$document\", \"$location\"];\n\n function AnalyticsService(rootscope, log, config, win, doc, location) {\n var conf;\n this.rootscope = rootscope;\n this.log = log;\n this.config = config;\n this.win = win;\n this.doc = doc;\n this.location = location;\n this.initialized = false;\n conf = this.config.get(\"analytics\", {});\n this.accountId = conf.accountId;\n this.pageEvent = conf.pageEvent || \"$routeChangeSuccess\";\n this.trackRoutes = conf.trackRoutes || true;\n this.ignoreFirstPageLoad = conf.ignoreFirstPageLoad || false;\n }\n\n AnalyticsService.prototype.initialize = function() {\n if (!this.accountId) {\n this.log.debug(\"Analytics: no acount id provided. Disabling.\");\n return;\n }\n this.injectAnalytics();\n this.win.ga(\"create\", this.accountId, \"auto\");\n this.win.ga(\"require\", \"displayfeatures\");\n if (this.trackRoutes && (!this.ignoreFirstPageLoad)) {\n this.win.ga(\"send\", \"pageview\", this.getUrl());\n }\n if (this.trackRoutes) {\n this.rootscope.$on(this.pageEvent, (function(_this) {\n return function() {\n return _this.trackPage(_this.getUrl(), \"Taiga\");\n };\n })(this));\n }\n return this.initialized = true;\n };\n\n AnalyticsService.prototype.getUrl = function() {\n return this.location.path();\n };\n\n AnalyticsService.prototype.injectAnalytics = function() {\n var fn;\n fn = (function(i,s,o,g,r,a,m){i[\"GoogleAnalyticsObject\"]=r;i[r]=i[r]||function(){\n (i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o),\n m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m);});\n return fn(window, document, \"script\", \"//www.google-analytics.com/analytics.js\", \"ga\");\n };\n\n AnalyticsService.prototype.trackPage = function(url, title) {\n if (!this.initialized) {\n return;\n }\n if (!this.win.ga) {\n return;\n }\n title = title || this.doc[0].title;\n return this.win.ga(\"send\", \"pageview\", {\n \"page\": url,\n \"title\": title\n });\n };\n\n AnalyticsService.prototype.trackEvent = function(category, action, label, value) {\n if (!this.initialized) {\n return;\n }\n if (!this.win.ga) {\n return;\n }\n return this.win.ga(\"send\", \"event\", category, action, label, value);\n };\n\n return AnalyticsService;\n\n })(taiga.Service);\n\n module.service(\"$tgAnalytics\", AnalyticsService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var AttachmentDirective, AttachmentsController, AttachmentsDirective, bindMethods, bindOnce, module, sizeFormat, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n bindOnce = this.taiga.bindOnce;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaCommon\");\n\n AttachmentsController = (function(_super) {\n __extends(AttachmentsController, _super);\n\n AttachmentsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$q\"];\n\n function AttachmentsController(scope, rootscope, repo, rs, confirm, q) {\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.rs = rs;\n this.confirm = confirm;\n this.q = q;\n bindMethods(this);\n this.type = null;\n this.objectId = null;\n this.projectId = null;\n this.uploadingAttachments = [];\n this.attachments = [];\n this.attachmentsCount = 0;\n this.deprecatedAttachmentsCount = 0;\n this.showDeprecated = false;\n }\n\n AttachmentsController.prototype.initialize = function(type, objectId) {\n this.type = type;\n this.objectId = objectId;\n return this.projectId = this.scope.projectId;\n };\n\n AttachmentsController.prototype.loadAttachments = function() {\n var urlname;\n if (!this.objectId) {\n return this.attachments;\n }\n urlname = \"attachments/\" + this.type;\n return this.rs.attachments.list(urlname, this.objectId, this.projectId).then((function(_this) {\n return function(attachments) {\n _this.attachments = _.sortBy(attachments, \"order\");\n _this.updateCounters();\n return attachments;\n };\n })(this));\n };\n\n AttachmentsController.prototype.updateCounters = function() {\n this.attachmentsCount = this.attachments.length;\n return this.deprecatedAttachmentsCount = _.filter(this.attachments, {\n is_deprecated: true\n }).length;\n };\n\n AttachmentsController.prototype._createAttachment = function(attachment) {\n var promise, urlName;\n urlName = \"attachments/\" + this.type;\n promise = this.rs.attachments.create(urlName, this.projectId, this.objectId, attachment);\n promise = promise.then((function(_this) {\n return function(data) {\n var index;\n data.isCreatedRightNow = true;\n index = _this.uploadingAttachments.indexOf(attachment);\n _this.uploadingAttachments.splice(index, 1);\n _this.attachments.push(data);\n return _this.rootscope.$broadcast(\"attachment:create\");\n };\n })(this));\n promise = promise.then(null, (function(_this) {\n return function(data) {\n var index;\n if (data.status === 413) {\n _this.scope.$emit(\"attachments:size-error\");\n }\n index = _this.uploadingAttachments.indexOf(attachment);\n _this.uploadingAttachments.splice(index, 1);\n _this.confirm.notify(\"error\", \"We have not been able to upload '\" + attachment.name + \"'. \" + data.data._error_message);\n return _this.q.reject(data);\n };\n })(this));\n return promise;\n };\n\n AttachmentsController.prototype.createAttachments = function(attachments) {\n var promises;\n promises = _.map(attachments, (function(_this) {\n return function(x) {\n return _this._createAttachment(x);\n };\n })(this));\n return this.q.all(promises).then((function(_this) {\n return function() {\n return _this.updateCounters();\n };\n })(this));\n };\n\n AttachmentsController.prototype.addUploadingAttachments = function(attachments) {\n return this.uploadingAttachments = _.union(this.uploadingAttachments, attachments);\n };\n\n AttachmentsController.prototype.reorderAttachment = function(attachment, newIndex) {\n var oldIndex;\n oldIndex = this.attachments.indexOf(attachment);\n if (oldIndex === newIndex) {\n return;\n }\n this.attachments.splice(oldIndex, 1);\n this.attachments.splice(newIndex, 0, attachment);\n return _.each(this.attachments, function(x, i) {\n return x.order = i + 1;\n });\n };\n\n AttachmentsController.prototype.updateAttachment = function(attachment) {\n var onError, onSuccess;\n onSuccess = (function(_this) {\n return function() {\n _this.updateCounters();\n return _this.rootscope.$broadcast(\"attachment:edit\");\n };\n })(this);\n onError = (function(_this) {\n return function(response) {\n if (response.status === 413) {\n $scope.$emit(\"attachments:size-error\");\n }\n _this.confirm.notify(\"error\");\n return _this.q.reject();\n };\n })(this);\n return this.repo.save(attachment).then(onSuccess, onError);\n };\n\n AttachmentsController.prototype.saveAttachments = function() {\n return this.repo.saveAll(this.attachments).then(null, (function(_this) {\n return function() {\n var item, _i, _len, _ref;\n _ref = _this.attachments;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n item = _ref[_i];\n item.revert();\n }\n return _this.attachments = _.sorBy(_this.attachments, \"order\");\n };\n })(this));\n };\n\n AttachmentsController.prototype.removeAttachment = function(attachment) {\n var message, title;\n title = \"Delete attachment\";\n message = \"the attachment '\" + attachment.name + \"'\";\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n var index;\n finish();\n index = _this.attachments.indexOf(attachment);\n _this.attachments.splice(index, 1);\n _this.updateCounters();\n return _this.rootscope.$broadcast(\"attachment:delete\");\n };\n onError = function() {\n finish(false);\n _this.confirm.notify(\"error\", null, \"We have not been able to delete \" + message + \".\");\n return _this.q.reject();\n };\n return _this.repo.remove(attachment).then(onSuccess, onError);\n };\n })(this));\n };\n\n AttachmentsController.prototype.filterAttachments = function(item) {\n if (this.showDeprecated) {\n return true;\n }\n return !item.is_deprecated;\n };\n\n return AttachmentsController;\n\n })(taiga.Controller);\n\n AttachmentsDirective = function($config, $confirm, $templates) {\n var link, template, templateFn;\n template = $templates.get(\"attachment/attachments.html\", true);\n link = function($scope, $el, $attrs, $ctrls) {\n var $ctrl, $model, showSizeInfo, tdom;\n $ctrl = $ctrls[0];\n $model = $ctrls[1];\n bindOnce($scope, $attrs.ngModel, function(value) {\n $ctrl.initialize($attrs.type, value.id);\n return $ctrl.loadAttachments();\n });\n tdom = $el.find(\"div.attachment-body.sortable\");\n tdom.sortable({\n items: \"div.single-attachment\",\n handle: \"a.settings.icon.icon-drag-v\",\n containment: \".attachments\",\n dropOnEmpty: true,\n scroll: false,\n tolerance: \"pointer\",\n placeholder: \"sortable-placeholder single-attachment\"\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var attachment, newIndex;\n attachment = ui.item.scope().attach;\n newIndex = ui.item.index();\n $ctrl.reorderAttachment(attachment, newIndex);\n return $ctrl.saveAttachments();\n });\n showSizeInfo = function() {\n return $el.find(\".size-info\").removeClass(\"hidden\");\n };\n $scope.$on(\"attachments:size-error\", function() {\n return showSizeInfo();\n });\n $el.on(\"change\", \".attachments-header input\", function(event) {\n var files;\n files = _.toArray(event.target.files);\n if (files.length < 1) {\n return;\n }\n return $scope.$apply(function() {\n $ctrl.addUploadingAttachments(files);\n return $ctrl.createAttachments(files);\n });\n });\n $el.on(\"click\", \".more-attachments\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n $scope.$apply(function() {\n return $ctrl.showDeprecated = !$ctrl.showDeprecated;\n });\n target.find(\"span.text\").addClass(\"hidden\");\n if ($ctrl.showDeprecated) {\n target.find(\"span[data-type=hide]\").removeClass(\"hidden\");\n return target.find(\"more-attachments-num\").addClass(\"hidden\");\n } else {\n target.find(\"span[data-type=show]\").removeClass(\"hidden\");\n return target.find(\"more-attachments-num\").removeClass(\"hidden\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n templateFn = function($el, $attrs) {\n var ctx, maxFileSize, maxFileSizeMsg;\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize) {\n maxFileSize = sizeFormat(maxFileSize);\n }\n maxFileSizeMsg = maxFileSize ? \"Maximum upload size is \" + maxFileSize : \"\";\n ctx = {\n type: $attrs.type,\n maxFileSize: maxFileSize,\n maxFileSizeMsg: maxFileSizeMsg\n };\n return template(ctx);\n };\n return {\n require: [\"tgAttachments\", \"ngModel\"],\n controller: AttachmentsController,\n controllerAs: \"ctrl\",\n restrict: \"AE\",\n scope: true,\n link: link,\n template: templateFn\n };\n };\n\n module.directive(\"tgAttachments\", [\"$tgConfig\", \"$tgConfirm\", \"$tgTemplate\", AttachmentsDirective]);\n\n AttachmentDirective = function($template) {\n var link, template, templateEdit;\n template = $template.get(\"attachment/attachment.html\", true);\n templateEdit = $template.get(\"attachment/attachment-edit.html\", true);\n link = function($scope, $el, $attrs, $ctrl) {\n var attachment, render, saveAttachment;\n render = function(attachment, edit) {\n var ctx, html, modifyPermission, permissions;\n if (edit == null) {\n edit = false;\n }\n permissions = $scope.project.my_permissions;\n modifyPermission = permissions.indexOf(\"modify_\" + $ctrl.type) > -1;\n ctx = {\n id: attachment.id,\n name: attachment.name,\n created_date: moment(attachment.created_date).format(\"DD MMM YYYY [at] hh:mm\"),\n url: attachment.url,\n size: sizeFormat(attachment.size),\n description: attachment.description,\n isDeprecated: attachment.is_deprecated,\n modifyPermission: modifyPermission\n };\n if (edit) {\n html = templateEdit(ctx);\n } else {\n html = template(ctx);\n }\n $el.html(html);\n if (attachment.is_deprecated) {\n $el.addClass(\"deprecated\");\n return $el.find(\"input:checkbox\").prop('checked', true);\n }\n };\n saveAttachment = function() {\n attachment.description = $el.find(\"input[name='description']\").val();\n attachment.is_deprecated = $el.find(\"input[name='is-deprecated']\").prop(\"checked\");\n return $scope.$apply(function() {\n return $ctrl.updateAttachment(attachment).then(function() {\n return render(attachment, false);\n });\n });\n };\n $el.on(\"click\", \"a.editable-settings.icon-floppy\", function(event) {\n event.preventDefault();\n return saveAttachment();\n });\n $el.on(\"keyup\", \"input[name=description]\", function(event) {\n if (event.keyCode === 13) {\n return saveAttachment();\n } else if (event.keyCode === 27) {\n return render(attachment, false);\n }\n });\n $el.on(\"click\", \"a.editable-settings.icon-delete\", function(event) {\n event.preventDefault();\n return render(attachment, false);\n });\n $el.on(\"click\", \"a.settings.icon-edit\", function(event) {\n event.preventDefault();\n render(attachment, true);\n return $el.find(\"input[name='description']\").focus().select();\n });\n $el.on(\"click\", \"a.settings.icon-delete\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n return $ctrl.removeAttachment(attachment);\n });\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n attachment = $scope.$eval($attrs.tgAttachment);\n render(attachment, attachment.isCreatedRightNow);\n if (attachment.isCreatedRightNow) {\n return $el.find(\"input[name='description']\").focus().select();\n }\n };\n return {\n link: link,\n require: \"^tgAttachments\",\n restrict: \"AE\"\n };\n };\n\n module.directive(\"tgAttachment\", [\"$tgTemplate\", AttachmentDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/components.coffee\n */\n\n(function() {\n var AssignedToDirective, BlockButtonDirective, CreatedByDisplayDirective, DateRangeDirective, DateSelectorDirective, DeleteButtonDirective, EditableDescriptionDirective, EditableSubjectDirective, ListItemAssignedtoDirective, ListItemIssueStatusDirective, ListItemPriorityDirective, ListItemSeverityDirective, ListItemTaskStatusDirective, ListItemTypeDirective, ListItemUsStatusDirective, SprintProgressBarDirective, TgMainTitleDirective, TgProgressBarDirective, WatchersDirective, bindOnce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n DateRangeDirective = function() {\n var link, renderRange;\n renderRange = function($el, first, second) {\n var endDate, initDate;\n initDate = moment(first).format(\"DD MMM YYYY\");\n endDate = moment(second).format(\"DD MMM YYYY\");\n return $el.html(\"\" + initDate + \"-\" + endDate);\n };\n link = function($scope, $el, $attrs) {\n var first, second, _ref;\n _ref = $attrs.tgDateRange.split(\",\"), first = _ref[0], second = _ref[1];\n return bindOnce($scope, first, function(valFirst) {\n return bindOnce($scope, second, function(valSecond) {\n return renderRange($el, valFirst, valSecond);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgDateRange\", DateRangeDirective);\n\n DateSelectorDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var selectedDate;\n selectedDate = null;\n $el.picker = new Pikaday({\n field: $el[0],\n format: \"DD MMM YYYY\",\n onSelect: (function(_this) {\n return function(date) {\n return selectedDate = date;\n };\n })(this),\n onOpen: (function(_this) {\n return function() {\n if (selectedDate != null) {\n return $el.picker.setDate(selectedDate);\n }\n };\n })(this)\n });\n return $scope.$watch($attrs.ngModel, function(val) {\n if (val != null) {\n return $el.picker.setDate(val);\n }\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgDateSelector\", DateSelectorDirective);\n\n SprintProgressBarDirective = function() {\n var link, renderProgress;\n renderProgress = function($el, percentage, visual_percentage) {\n if ($el.hasClass(\".current-progress\")) {\n return $el.css(\"width\", \"\" + percentage + \"%\");\n } else {\n $el.find(\".current-progress\").css(\"width\", \"\" + visual_percentage + \"%\");\n return $el.find(\".number\").html(\"\" + percentage + \" %\");\n }\n };\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgSprintProgressbar, function(sprint) {\n var closedPoints, percentage, totalPoints, visual_percentage;\n closedPoints = sprint.closed_points;\n totalPoints = sprint.total_points;\n percentage = 0;\n if (totalPoints !== 0) {\n percentage = Math.round(100 * (closedPoints / totalPoints));\n }\n visual_percentage = 0;\n if (totalPoints !== 0) {\n visual_percentage = Math.round(98 * (closedPoints / totalPoints));\n }\n return renderProgress($el, percentage, visual_percentage);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSprintProgressbar\", SprintProgressBarDirective);\n\n CreatedByDisplayDirective = function($template) {\n var link, template;\n template = $template.get(\"common/components/created-by.html\", true);\n link = function($scope, $el, $attrs) {\n var render;\n render = function(model) {\n var html, owner, _ref;\n owner = ((_ref = $scope.usersById) != null ? _ref[model.owner] : void 0) || {\n full_name_display: \"external user\",\n photo: \"/images/unnamed.png\"\n };\n html = template({\n owner: owner,\n date: moment(model.created_date).format(\"DD MMM YYYY HH:mm\")\n });\n return $el.html(html);\n };\n bindOnce($scope, $attrs.ngModel, function(model) {\n if (model != null) {\n return render(model);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgCreatedByDisplay\", [\"$tgTemplate\", CreatedByDisplayDirective]);\n\n WatchersDirective = function($rootscope, $confirm, $repo, $qqueue, $template) {\n var link, template;\n template = $template.get(\"common/components/watchers.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var deleteWatcher, isEditable, renderWatchers, save;\n isEditable = function() {\n var _ref, _ref1;\n return ((_ref = $scope.project) != null ? (_ref1 = _ref.my_permissions) != null ? _ref1.indexOf($attrs.requiredPerm) : void 0 : void 0) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(watchers) {\n var item, promise;\n item = $model.$modelValue.clone();\n item.watchers = watchers;\n $model.$setViewValue(item);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n watchers = _.map(watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n renderWatchers(watchers);\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n return $model.$modelValue.revert();\n });\n };\n })(this));\n deleteWatcher = $qqueue.bindAdd((function(_this) {\n return function(watcherIds) {\n var item, promise;\n item = $model.$modelValue.clone();\n item.watchers = watcherIds;\n $model.$setViewValue(item);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n var watchers;\n $confirm.notify(\"success\");\n watchers = _.map(item.watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n renderWatchers(watchers);\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n item.revert();\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n renderWatchers = function(watchers) {\n var ctx, html;\n ctx = {\n watchers: watchers,\n isEditable: isEditable()\n };\n html = template(ctx);\n $el.html(html);\n if (isEditable() && watchers.length === 0) {\n $el.find(\".title\").text(\"Add watchers\");\n return $el.find(\".watchers-header\").addClass(\"no-watchers\");\n }\n };\n $el.on(\"click\", \".icon-delete\", function(event) {\n var message, target, title, watcherId;\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n watcherId = target.data(\"watcher-id\");\n title = \"Delete watcher\";\n message = $scope.usersById[watcherId].full_name_display;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var watcherIds;\n finish();\n watcherIds = _.clone($model.$modelValue.watchers, false);\n watcherIds = _.pull(watcherIds, watcherId);\n return deleteWatcher(watcherIds);\n };\n })(this));\n });\n $el.on(\"click\", \".add-watcher\", function(event) {\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"watcher:add\", $model.$modelValue);\n });\n });\n $scope.$on(\"watcher:added\", function(ctx, watcherId) {\n var watchers;\n watchers = _.clone($model.$modelValue.watchers, false);\n watchers.push(watcherId);\n watchers = _.uniq(watchers);\n return save(watchers);\n });\n $scope.$watch($attrs.ngModel, function(item) {\n var watchers;\n if (item == null) {\n return;\n }\n watchers = _.map(item.watchers, function(watcherId) {\n return $scope.usersById[watcherId];\n });\n return renderWatchers(watchers);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgWatchers\", [\"$rootScope\", \"$tgConfirm\", \"$tgRepo\", \"$tgQqueue\", \"$tgTemplate\", WatchersDirective]);\n\n AssignedToDirective = function($rootscope, $confirm, $repo, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"common/components/assigned-to.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, renderAssignedTo, save;\n isEditable = function() {\n var _ref, _ref1;\n return ((_ref = $scope.project) != null ? (_ref1 = _ref.my_permissions) != null ? _ref1.indexOf($attrs.requiredPerm) : void 0 : void 0) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(userId) {\n var promise;\n $model.$modelValue.assigned_to = userId;\n $loading.start($el);\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el);\n $confirm.notify(\"success\");\n renderAssignedTo($model.$modelValue);\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n $model.$modelValue.revert();\n $confirm.notify(\"error\");\n return $loading.finish($el);\n });\n return promise;\n };\n })(this));\n renderAssignedTo = function(issue) {\n var assignedTo, assignedToId, ctx, html;\n assignedToId = issue != null ? issue.assigned_to : void 0;\n assignedTo = assignedToId != null ? $scope.usersById[assignedToId] : null;\n ctx = {\n assignedTo: assignedTo,\n isEditable: isEditable()\n };\n html = template(ctx);\n return $el.html(html);\n };\n $el.on(\"click\", \".user-assigned\", function(event) {\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"assigned-to:add\", $model.$modelValue);\n });\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var title;\n event.preventDefault();\n if (!isEditable()) {\n return;\n }\n title = \"Are you sure you want to leave it unassigned?\";\n return $confirm.ask(title).then((function(_this) {\n return function(finish) {\n finish();\n $model.$modelValue.assigned_to = null;\n return save(null);\n };\n })(this));\n });\n $scope.$on(\"assigned-to:added\", function(ctx, userId, item) {\n if (item.id !== $model.$modelValue.id) {\n return;\n }\n return save(userId);\n });\n $scope.$watch($attrs.ngModel, function(instance) {\n return renderAssignedTo(instance);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgAssignedTo\", [\"$rootScope\", \"$tgConfirm\", \"$tgRepo\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", AssignedToDirective]);\n\n BlockButtonDirective = function($rootscope, $loading, $template) {\n var link, template;\n template = $template.get(\"common/components/block-button.html\");\n link = function($scope, $el, $attrs, $model) {\n var isEditable;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n $scope.$watch($attrs.ngModel, function(item) {\n if (!item) {\n return;\n }\n if (isEditable()) {\n $el.find('.item-block').addClass('editable');\n }\n if (item.is_blocked) {\n $el.find('.item-block').hide();\n return $el.find('.item-unblock').show();\n } else {\n $el.find('.item-block').show();\n return $el.find('.item-unblock').hide();\n }\n });\n $el.on(\"click\", \".item-block\", function(event) {\n event.preventDefault();\n return $rootscope.$broadcast(\"block\", $model.$modelValue);\n });\n $el.on(\"click\", \".item-unblock\", function(event) {\n var finish;\n event.preventDefault();\n $loading.start($el.find(\".item-unblock\"));\n finish = function() {\n return $loading.finish($el.find(\".item-unblock\"));\n };\n return $rootscope.$broadcast(\"unblock\", $model.$modelValue, finish);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgBlockButton\", [\"$rootScope\", \"$tgLoading\", \"$tgTemplate\", BlockButtonDirective]);\n\n DeleteButtonDirective = function($log, $repo, $confirm, $location, $template) {\n var link, template;\n template = $template.get(\"common/components/delete-button.html\");\n link = function($scope, $el, $attrs, $model) {\n if (!$attrs.onDeleteGoToUrl) {\n return $log.error(\"DeleteButtonDirective requires on-delete-go-to-url set in scope.\");\n }\n if (!$attrs.onDeleteTitle) {\n return $log.error(\"DeleteButtonDirective requires on-delete-title set in scope.\");\n }\n $el.on(\"click\", \".button\", function(event) {\n var subtitle, title;\n title = $scope.$eval($attrs.onDeleteTitle);\n subtitle = $model.$modelValue.subject;\n return $confirm.askOnDelete(title, subtitle).then((function(_this) {\n return function(finish) {\n var promise;\n promise = $repo.remove($model.$modelValue);\n promise.then(function() {\n var url;\n finish();\n url = $scope.$eval($attrs.onDeleteGoToUrl);\n return $location.path(url);\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgDeleteButton\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", \"$tgTemplate\", DeleteButtonDirective]);\n\n EditableSubjectDirective = function($rootscope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"common/components/editable-subject.html\");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(subject) {\n var promise;\n $model.$modelValue.subject = subject;\n $loading.start($el.find('.save-container'));\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $el.find('.edit-subject').hide();\n return $el.find('.view-subject').show();\n });\n promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n return promise;\n };\n })(this));\n $el.click(function() {\n if (!isEditable()) {\n return;\n }\n $el.find('.edit-subject').show();\n $el.find('.view-subject').hide();\n return $el.find('input').focus();\n });\n $el.on(\"click\", \".save\", function() {\n var subject;\n subject = $scope.item.subject;\n return save(subject);\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var subject;\n if (event.keyCode === 13) {\n subject = $scope.item.subject;\n return save(subject);\n } else if (event.keyCode === 27) {\n $scope.$apply((function(_this) {\n return function() {\n return $model.$modelValue.revert();\n };\n })(this));\n $el.find('div.edit-subject').hide();\n return $el.find('div.view-subject').show();\n }\n });\n $el.find('div.edit-subject').hide();\n $el.find('div.view-subject span.edit').hide();\n $scope.$watch($attrs.ngModel, function(value) {\n if (!value) {\n return;\n }\n $scope.item = value;\n if (!isEditable()) {\n return $el.find('.view-subject .edit').remove();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgEditableSubject\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", EditableSubjectDirective]);\n\n EditableDescriptionDirective = function($rootscope, $repo, $confirm, $compile, $loading, $selectedText, $qqueue, $template) {\n var link, noDescriptionMegEditMode, noDescriptionMegReadMode, template;\n template = $template.get(\"common/components/editable-description.html\");\n noDescriptionMegEditMode = $template.get(\"common/components/editable-description-msg-edit-mode.html\");\n noDescriptionMegReadMode = $template.get(\"common/components/editable-description-msg-read-mode.html\");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, save;\n $el.find('.edit-description').hide();\n $el.find('.view-description .edit').hide();\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(description) {\n var promise;\n $model.$modelValue.description = description;\n $loading.start($el.find('.save-container'));\n promise = $repo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $el.find('.edit-description').hide();\n return $el.find('.view-description').show();\n });\n promise.then(null, function() {\n return $confirm.notify(\"error\");\n });\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n };\n })(this));\n $el.on(\"mouseup\", \".view-description\", function(event) {\n var target;\n target = angular.element(event.target);\n if (!isEditable()) {\n return;\n }\n if (target.is('a')) {\n return;\n }\n if ($selectedText.get().length) {\n return;\n }\n $el.find('.edit-description').show();\n $el.find('.view-description').hide();\n return $el.find('textarea').focus();\n });\n $el.on(\"click\", \".save\", function() {\n var description;\n description = $scope.item.description;\n return save(description);\n });\n $el.on(\"keydown\", \"textarea\", function(event) {\n if (event.keyCode === 27) {\n $scope.$apply((function(_this) {\n return function() {\n return $scope.item.revert();\n };\n })(this));\n $el.find('.edit-description').hide();\n return $el.find('.view-description').show();\n }\n });\n $scope.$watch($attrs.ngModel, function(value) {\n if (!value) {\n return;\n }\n $scope.item = value;\n if (isEditable()) {\n $el.find('.view-description .edit').show();\n $el.find('.view-description .us-content').addClass('editable');\n return $scope.noDescriptionMsg = noDescriptionMegEditMode;\n } else {\n return $scope.noDescriptionMsg = noDescriptionMegReadMode;\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n template: template\n };\n };\n\n module.directive(\"tgEditableDescription\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$compile\", \"$tgLoading\", \"$selectedText\", \"$tgQqueue\", \"$tgTemplate\", EditableDescriptionDirective]);\n\n ListItemIssueStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemIssueStatus);\n return bindOnce($scope, \"issueStatusById\", function(issueStatusById) {\n return $el.html(issueStatusById[issue.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemTaskStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var task;\n task = $scope.$eval($attrs.tgListitemTaskStatus);\n return bindOnce($scope, \"taskStatusById\", function(taskStatusById) {\n return $el.html(taskStatusById[task.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemUsStatusDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var us;\n us = $scope.$eval($attrs.tgListitemUsStatus);\n return bindOnce($scope, \"usStatusById\", function(usStatusById) {\n return $el.html(usStatusById[us.status].name);\n });\n };\n return {\n link: link\n };\n };\n\n ListItemAssignedtoDirective = function($template) {\n var link, template;\n template = $template.get(\"common/components/list-item-assigned-to-avatar.html\", true);\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, \"membersById\", function(membersById) {\n var ctx, item, member;\n item = $scope.$eval($attrs.tgListitemAssignedto);\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = membersById[item.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name;\n }\n return $el.html(template(ctx));\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgListitemAssignedto\", [\"$tgTemplate\", ListItemAssignedtoDirective]);\n\n ListItemPriorityDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var render;\n render = function(priorityById, issue) {\n var domNode, priority;\n priority = priorityById[issue.priority];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", priority.color);\n return domNode.attr(\"title\", priority.name);\n };\n bindOnce($scope, \"priorityById\", function(priorityById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemPriority);\n return render(priorityById, issue);\n });\n return $scope.$watch($attrs.tgListitemPriority, function(issue) {\n return render($scope.priorityById, issue);\n });\n };\n return {\n link: link,\n templateUrl: \"common/components/level.html\"\n };\n };\n\n module.directive(\"tgListitemPriority\", ListItemPriorityDirective);\n\n ListItemSeverityDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var render;\n render = function(severityById, issue) {\n var domNode, severity;\n severity = severityById[issue.severity];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", severity.color);\n return domNode.attr(\"title\", severity.name);\n };\n bindOnce($scope, \"severityById\", function(severityById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemSeverity);\n return render(severityById, issue);\n });\n return $scope.$watch($attrs.tgListitemSeverity, function(issue) {\n return render($scope.severityById, issue);\n });\n };\n return {\n link: link,\n templateUrl: \"common/components/level.html\"\n };\n };\n\n ListItemTypeDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var render;\n render = function(issueTypeById, issue) {\n var domNode, type;\n type = issueTypeById[issue.type];\n domNode = $el.find(\".level\");\n domNode.css(\"background-color\", type.color);\n return domNode.attr(\"title\", type.name);\n };\n bindOnce($scope, \"issueTypeById\", function(issueTypeById) {\n var issue;\n issue = $scope.$eval($attrs.tgListitemType);\n return render(issueTypeById, issue);\n });\n return $scope.$watch($attrs.tgListitemType, function(issue) {\n return render($scope.issueTypeById, issue);\n });\n };\n return {\n link: link,\n templateUrl: \"common/components/level.html\"\n };\n };\n\n TgProgressBarDirective = function($template) {\n var link, render, template;\n template = $template.get(\"common/components/progress-bar.html\", true);\n render = function(el, percentage) {\n return el.html(template({\n percentage: percentage\n }));\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch($attrs.tgProgressBar, function(percentage) {\n percentage = _.max([0, percentage]);\n percentage = _.min([100, percentage]);\n return render($el, percentage);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProgressBar\", [\"$tgTemplate\", TgProgressBarDirective]);\n\n TgMainTitleDirective = function($template) {\n var link, render, template;\n template = $template.get(\"common/components/main-title.html\", true);\n render = function(el, projectName, sectionName) {\n return el.html(template({\n projectName: projectName,\n sectionName: sectionName\n }));\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch(\"project\", function(project) {\n if (project) {\n return render($el, project.name, $scope.sectionName);\n }\n });\n $scope.$on(\"project:loaded\", (function(_this) {\n return function(ctx, project) {\n return render($el, project.name, $scope.sectionName);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMainTitle\", [\"$tgTemplate\", TgMainTitleDirective]);\n\n module.directive(\"tgListitemType\", ListItemTypeDirective);\n\n module.directive(\"tgListitemIssueStatus\", ListItemIssueStatusDirective);\n\n module.directive(\"tgListitemSeverity\", ListItemSeverityDirective);\n\n module.directive(\"tgListitemTaskStatus\", ListItemTaskStatusDirective);\n\n module.directive(\"tgListitemUsStatus\", ListItemUsStatusDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/confirm.coffee\n */\n\n(function() {\n var ConfirmService, NOTIFICATION_MSG, bindMethods, cancelTimeout, debounce, module, taiga, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n timeout = this.taiga.timeout;\n\n cancelTimeout = this.taiga.cancelTimeout;\n\n debounce = this.taiga.debounce;\n\n bindMethods = this.taiga.bindMethods;\n\n NOTIFICATION_MSG = {\n \"success\": {\n title: \"Everything is ok\",\n message: \"Our Oompa Loompas saved all your changes!\"\n },\n \"error\": {\n title: \"Oops, something happened...\",\n message: \"Our Oompa Loompas are sad, your changes were not saved!\"\n },\n \"light-error\": {\n title: \"Oops, something happened...\",\n message: \"Our Oompa Loompas are sad, your changes were not saved!\"\n }\n };\n\n ConfirmService = (function(_super) {\n __extends(ConfirmService, _super);\n\n ConfirmService.$inject = [\"$q\", \"lightboxService\", \"$tgLoading\"];\n\n function ConfirmService(q, lightboxService, loading) {\n this.q = q;\n this.lightboxService = lightboxService;\n this.loading = loading;\n bindMethods(this);\n }\n\n ConfirmService.prototype.hide = function(el) {\n if (el) {\n this.lightboxService.close(el);\n return el.off(\".confirm-dialog\");\n }\n };\n\n ConfirmService.prototype.ask = function(title, subtitle, message, lightboxSelector) {\n var defered, el;\n if (lightboxSelector == null) {\n lightboxSelector = \".lightbox-generic-ask\";\n }\n el = angular.element(lightboxSelector);\n el.find(\"h2.title\").html(title);\n el.find(\"span.subtitle\").html(subtitle);\n el.find(\"span.message\").html(message);\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", debounce(2000, (function(_this) {\n return function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n _this.loading.start(target);\n return defered.resolve(function(ok) {\n if (ok == null) {\n ok = true;\n }\n _this.loading.finish(target);\n if (ok) {\n return _this.hide(el);\n }\n });\n };\n })(this)));\n el.on(\"click.confirm-dialog\", \"a.button-red\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.reject();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.askOnDelete = function(title, message) {\n return this.ask(title, \"Are you sure you want to delete?\", message);\n };\n\n ConfirmService.prototype.askChoice = function(title, subtitle, choices, replacement, warning, lightboxSelector) {\n var choicesField, defered, el;\n if (lightboxSelector == null) {\n lightboxSelector = \".lightbox-ask-choice\";\n }\n el = angular.element(lightboxSelector);\n el.find(\".title\").html(title);\n el.find(\".subtitle\").html(subtitle);\n if (replacement) {\n el.find(\".replacement\").html(replacement);\n } else {\n el.find(\".replacement\").remove();\n }\n if (warning) {\n el.find(\".warning\").html(warning);\n } else {\n el.find(\".warning\").remove();\n }\n choicesField = el.find(\".choices\");\n choicesField.html('');\n _.each(choices, function(value, key) {\n return choicesField.append(angular.element(\"\"));\n });\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", debounce(2000, (function(_this) {\n return function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n _this.loading.start(target);\n return defered.resolve({\n selected: choicesField.val(),\n finish: function() {\n _this.loading.finish(target);\n return _this.hide(el);\n }\n });\n };\n })(this)));\n el.on(\"click.confirm-dialog\", \"a.button-red\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.reject();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.error = function(message) {\n var defered, el;\n el = angular.element(\".lightbox-generic-error\");\n el.find(\"h2.title\").html(message);\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n el.on(\"click.confirm-dialog\", \"a.close\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.success = function(title, message) {\n var defered, el;\n el = angular.element(\".lightbox-generic-success\");\n if (title) {\n el.find(\"h2.title\").html(title);\n }\n if (message) {\n el.find(\"p.message\").html(message);\n }\n defered = this.q.defer();\n el.on(\"click.confirm-dialog\", \"a.button-green\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n el.on(\"click.confirm-dialog\", \"a.close\", (function(_this) {\n return function(event) {\n event.preventDefault();\n defered.resolve();\n return _this.hide(el);\n };\n })(this));\n this.lightboxService.open(el);\n return defered.promise;\n };\n\n ConfirmService.prototype.loader = function(title, message) {\n var el;\n el = angular.element(\".lightbox-generic-loading\");\n if (title) {\n el.find(\"h2.title\").html(title);\n }\n if (message) {\n el.find(\"p.message\").html(message);\n }\n return {\n start: (function(_this) {\n return function() {\n return _this.lightboxService.open(el);\n };\n })(this),\n stop: (function(_this) {\n return function() {\n return _this.lightboxService.close(el);\n };\n })(this),\n update: (function(_this) {\n return function(status, title, message, percent) {\n if (title) {\n el.find(\"h2.title\").html(title);\n }\n if (message) {\n el.find(\"p.message\").html(message);\n }\n if (percent) {\n el.find(\".spin\").addClass(\"hidden\");\n el.find(\".progress-bar-wrapper\").removeClass(\"hidden\");\n el.find(\".progress-bar-wrapper > .bar\").width(percent + '%');\n return el.find(\".progress-bar-wrapper > span\").html(percent + '%').css('left', (percent - 9) + '%');\n } else {\n el.find(\".spin\").removeClass(\"hidden\");\n return el.find(\".progress-bar-wrapper\").addClass(\"hidden\");\n }\n };\n })(this)\n };\n };\n\n ConfirmService.prototype.notify = function(type, message, title, time) {\n var body, el, selector;\n selector = \".notification-message-\" + type;\n el = angular.element(selector);\n if (el.hasClass(\"active\")) {\n return;\n }\n if (title) {\n el.find(\"h4\").html(title);\n } else {\n el.find(\"h4\").html(NOTIFICATION_MSG[type].title);\n }\n if (message) {\n el.find(\"p\").html(message);\n } else {\n el.find(\"p\").html(NOTIFICATION_MSG[type].message);\n }\n body = angular.element(\"body\");\n body.find(\".notification-message .notification-light\").removeClass('active').addClass('inactive');\n body.find(selector).removeClass('inactive').addClass('active');\n if (this.tsem) {\n cancelTimeout(this.tsem);\n }\n if (!time) {\n time = type === 'error' || type === 'light-error' ? 3500 : 1500;\n }\n this.tsem = timeout(time, (function(_this) {\n return function() {\n body.find(selector).removeClass('active').addClass('inactive');\n return delete _this.tsem;\n };\n })(this));\n return el.on(\"click\", \".icon-delete\", (function(_this) {\n return function(event) {\n return body.find(selector).removeClass('active').addClass('inactive');\n };\n })(this));\n };\n\n return ConfirmService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaCommon\");\n\n module.service(\"$tgConfirm\", ConfirmService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/estimation.coffee\n */\n\n(function() {\n var LbUsEstimationDirective, UsEstimationDirective, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n LbUsEstimationDirective = function($rootScope, $repo, $confirm, $template) {\n var link, mainTemplate, pointsTemplate;\n mainTemplate = $template.get(\"common/estimation/lb-us-estimation-points-per-role.html\", true);\n pointsTemplate = $template.get(\"common/estimation/lb-us-estimation-points.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var calculateTotalPoints, render, renderPoints;\n render = function(points) {\n var computableRoles, ctx, html, roles, totalPoints;\n totalPoints = calculateTotalPoints(points) || 0;\n computableRoles = _.filter($scope.project.roles, \"computable\");\n roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = (pointObj != null) && (pointObj.name != null) ? pointObj.name : \"?\";\n return role;\n });\n ctx = {\n totalPoints: totalPoints,\n roles: roles\n };\n html = mainTemplate(ctx);\n return $el.html(html);\n };\n renderPoints = function(target, usPoints, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = usPoints[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points,\n roleId: roleId\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n $el.find(\".pop-points-open\").remove();\n $el.find(target).append(html);\n $el.find(\".pop-points-open\").popover().open(function() {\n return $(this).removeClass(\"active\");\n });\n return $el.find(\".pop-points-open\").show();\n };\n calculateTotalPoints = function(points) {\n var values;\n values = _.map(points, function(v, k) {\n var _ref;\n return ((_ref = $scope.pointsById[v]) != null ? _ref.value : void 0) || 0;\n });\n if (values.length === 0) {\n return \"0\";\n }\n return _.reduce(values, function(acc, num) {\n return acc + num;\n });\n };\n $el.on(\"click\", \".total.clickable\", function(event) {\n var points, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n points = $model.$modelValue;\n renderPoints(target, points, roleId);\n target.siblings().removeClass('active');\n return target.addClass('active');\n });\n $el.on(\"click\", \".point\", function(event) {\n var pointId, points, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n pointId = target.data(\"point-id\");\n $el.find(\".popover\").popover().close();\n points = _.clone($model.$modelValue, true);\n points[roleId] = pointId;\n return $scope.$apply(function() {\n return $model.$setViewValue(points);\n });\n });\n $scope.$watch($attrs.ngModel, function(points) {\n if (points) {\n return render(points);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgLbUsEstimation\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgTemplate\", LbUsEstimationDirective]);\n\n UsEstimationDirective = function($rootScope, $repo, $confirm, $qqueue, $template) {\n var link, mainTemplate, pointsTemplate;\n mainTemplate = $template.get(\"common/estimation/us-estimation-points-per-role.html\", true);\n pointsTemplate = $template.get(\"common/estimation/us-estimation-points.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var calculateTotalPoints, isEditable, render, renderPoints, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var computableRoles, ctx, html, roles, totalPoints;\n totalPoints = us.total_points != null ? us.total_points : \"?\";\n computableRoles = _.filter($scope.project.roles, \"computable\");\n roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = us.points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = (pointObj != null) && (pointObj.name != null) ? pointObj.name : \"?\";\n return role;\n });\n ctx = {\n totalPoints: totalPoints,\n roles: roles,\n editable: isEditable()\n };\n html = mainTemplate(ctx);\n return $el.html(html);\n };\n renderPoints = function(target, us, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = us.points[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points,\n roleId: roleId\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n $el.find(\".pop-points-open\").remove();\n $el.find(target).append(html);\n $el.find(\".pop-points-open\").popover().open(function() {\n return $(this).removeClass(\"active\").closest(\"li\").removeClass(\"active\");\n });\n return $el.find(\".pop-points-open\").show();\n };\n calculateTotalPoints = function(us) {\n var notNullValues, values;\n values = _.map(us.points, function(v, k) {\n var _ref;\n return (_ref = $scope.pointsById[v]) != null ? _ref.value : void 0;\n });\n if (values.length === 0) {\n return \"0\";\n }\n notNullValues = _.filter(values, function(v) {\n return v != null;\n });\n if (notNullValues.length === 0) {\n return \"?\";\n }\n return _.reduce(notNullValues, function(acc, num) {\n return acc + num;\n });\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(roleId, pointId) {\n var onError, onSuccess, points, us;\n $el.find(\".popover\").popover().close();\n us = angular.copy($model.$modelValue);\n points = _.clone($model.$modelValue.points, true);\n points[roleId] = pointId;\n us.setAttr('points', points);\n us.points = points;\n us.total_points = calculateTotalPoints(us);\n $model.$setViewValue(us);\n onSuccess = function() {\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n };\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".total.clickable\", function(event) {\n var roleId, target, us;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n us = $model.$modelValue;\n renderPoints(target, us, roleId);\n target.siblings().removeClass('active');\n return target.addClass('active');\n });\n $el.on(\"click\", \".point\", function(event) {\n var pointId, roleId, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n roleId = target.data(\"role-id\");\n pointId = target.data(\"point-id\");\n return save(roleId, pointId);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsEstimation\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgQqueue\", \"$tgTemplate\", UsEstimationDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/filters.coffee\n */\n\n(function() {\n var defaultFilter, module, momentFormat, momentFromNow, taiga, unslugify, yesNoFilter;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n defaultFilter = function() {\n return function(value, defaultValue) {\n if (value === [null, void 0]) {\n return defaultValue;\n }\n return value;\n };\n };\n\n module.filter(\"default\", defaultFilter);\n\n yesNoFilter = function() {\n return function(value) {\n if (value) {\n return \"Yes\";\n }\n return \"No\";\n };\n };\n\n module.filter(\"yesNo\", yesNoFilter);\n\n unslugify = function() {\n return taiga.unslugify;\n };\n\n module.filter(\"unslugify\", unslugify);\n\n momentFormat = function() {\n return function(input, format) {\n if (input) {\n return moment(input).format(format);\n }\n return \"\";\n };\n };\n\n module.filter(\"momentFormat\", momentFormat);\n\n momentFromNow = function() {\n return function(input, without_suffix) {\n if (input) {\n return moment(input).fromNow(without_suffix || false);\n }\n return \"\";\n };\n };\n\n module.filter(\"momentFromNow\", momentFromNow);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/history.coffee\n */\n\n(function() {\n var HistoryController, HistoryDirective, bindOnce, debounce, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaCommon\");\n\n HistoryController = (function(_super) {\n __extends(HistoryController, _super);\n\n HistoryController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\"];\n\n function HistoryController(scope, repo, rs) {\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n }\n\n HistoryController.prototype.initialize = function(type, objectId) {\n this.type = type;\n return this.objectId = objectId;\n };\n\n HistoryController.prototype.loadHistory = function(type, objectId) {\n return this.rs.history.get(type, objectId).then((function(_this) {\n return function(history) {\n var historyResult, _i, _len;\n for (_i = 0, _len = history.length; _i < _len; _i++) {\n historyResult = history[_i];\n if (historyResult.values_diff.description_diff != null) {\n historyResult.values_diff.description = historyResult.values_diff.description_diff;\n }\n delete historyResult.values_diff.description_html;\n delete historyResult.values_diff.description_diff;\n }\n _this.scope.history = history;\n return _this.scope.comments = _.filter(history, function(item) {\n return item.comment !== \"\";\n });\n };\n })(this));\n };\n\n HistoryController.prototype.deleteComment = function(type, objectId, activityId) {\n return this.rs.history.deleteComment(type, objectId, activityId).then((function(_this) {\n return function() {\n return _this.loadHistory(type, objectId);\n };\n })(this));\n };\n\n HistoryController.prototype.undeleteComment = function(type, objectId, activityId) {\n return this.rs.history.undeleteComment(type, objectId, activityId).then((function(_this) {\n return function() {\n return _this.loadHistory(type, objectId);\n };\n })(this));\n };\n\n return HistoryController;\n\n })(taiga.Controller);\n\n HistoryDirective = function($log, $loading, $qqueue, $template) {\n var link, templateActivity, templateBase, templateBaseEntries, templateChangeAttachment, templateChangeDiff, templateChangeGeneric, templateChangePoints, templateDeletedComment, templateFn;\n templateChangeDiff = $template.get(\"common/history/history-change-diff.html\", true);\n templateChangePoints = $template.get(\"common/history/history-change-points.html\", true);\n templateChangeGeneric = $template.get(\"common/history/history-change-generic.html\", true);\n templateChangeAttachment = $template.get(\"common/history/history-change-attachment.html\", true);\n templateDeletedComment = $template.get(\"common/history/history-deleted-comment.html\", true);\n templateActivity = $template.get(\"common/history/history-activity.html\", true);\n templateBaseEntries = $template.get(\"common/history/history-base-entries.html\", true);\n templateBase = $template.get(\"common/history/history-base.html\", true);\n link = function($scope, $el, $attrs, $ctrl) {\n var countChanges, formatChange, getHumanizedFieldName, getUserAvatar, getUserFullName, objectId, renderActivity, renderAttachmentEntry, renderChange, renderChangeEntries, renderChangeEntry, renderChangesHelperText, renderComment, renderComments, renderHistory, save, showAllActivity, showAllComments, type;\n type = $attrs.type;\n objectId = null;\n showAllComments = false;\n showAllActivity = false;\n bindOnce($scope, $attrs.ngModel, function(model) {\n type = $attrs.type;\n objectId = model.id;\n $ctrl.initialize(type, objectId);\n return $ctrl.loadHistory(type, objectId);\n });\n getHumanizedFieldName = function(field) {\n var humanizedFieldNames;\n humanizedFieldNames = {\n assigned_to: \"assigned to\",\n is_closed: \"is closed\",\n finish_date: \"finish date\",\n client_requirement: \"client requirement\",\n team_requirement: \"team requirement\",\n milestone: \"sprint\",\n user_story: \"user story\",\n is_iocaine: \"is iocaine\",\n is_deprecated: \"is deprecated\"\n };\n return humanizedFieldNames[field] || field;\n };\n getUserFullName = function(userId) {\n var _ref;\n return (_ref = $scope.usersById[userId]) != null ? _ref.full_name_display : void 0;\n };\n getUserAvatar = function(userId) {\n if ($scope.usersById[userId] != null) {\n return $scope.usersById[userId].photo;\n } else {\n return \"/images/unnamed.png\";\n }\n };\n countChanges = function(comment) {\n return _.keys(comment.values_diff).length;\n };\n formatChange = function(change) {\n if (_.isArray(change)) {\n if (change.length === 0) {\n return \"nil\";\n }\n return change.join(\", \");\n }\n if (change === \"\") {\n return \"nil\";\n }\n if (change === true) {\n return \"yes\";\n }\n if (change === false) {\n return \"no\";\n }\n return change;\n };\n renderAttachmentEntry = function(value) {\n var attachments;\n attachments = _.map(value, function(changes, type) {\n if (type === \"new\") {\n return _.map(changes, function(change) {\n return templateChangeDiff({\n name: \"new attachment\",\n diff: change.filename\n });\n });\n } else if (type === \"deleted\") {\n return _.map(changes, function(change) {\n return templateChangeDiff({\n name: \"deleted attachment\",\n diff: change.filename\n });\n });\n } else {\n return _.map(changes, function(change) {\n var diff, name;\n name = \"updated attachment \" + change.filename;\n diff = _.map(change.changes, function(values, name) {\n return {\n name: getHumanizedFieldName(name),\n from: formatChange(values[0]),\n to: formatChange(values[1])\n };\n });\n return templateChangeAttachment({\n name: name,\n diff: diff\n });\n });\n }\n });\n return _.flatten(attachments).join(\"\\n\");\n };\n renderChangeEntry = function(field, value) {\n var from, name, to;\n if (field === \"description\") {\n return templateChangeDiff({\n name: \"description\",\n diff: value[1]\n });\n } else if (field === \"points\") {\n return templateChangePoints({\n points: value\n });\n } else if (field === \"attachments\") {\n return renderAttachmentEntry(value);\n } else if (field === \"assigned_to\") {\n name = getHumanizedFieldName(field);\n from = formatChange(value[0] || \"Unassigned\");\n to = formatChange(value[1] || \"Unassigned\");\n return templateChangeGeneric({\n name: name,\n from: from,\n to: to\n });\n } else {\n name = getHumanizedFieldName(field);\n from = formatChange(value[0]);\n to = formatChange(value[1]);\n return templateChangeGeneric({\n name: name,\n from: from,\n to: to\n });\n }\n };\n renderChangeEntries = function(change, join) {\n var entries;\n if (join == null) {\n join = true;\n }\n entries = _.map(change.values_diff, function(value, field) {\n return renderChangeEntry(field, value);\n });\n if (join) {\n return entries.join(\"\\n\");\n }\n return entries;\n };\n renderChangesHelperText = function(change) {\n var size;\n size = countChanges(change);\n if (size === 1) {\n return \"Made \" + size + \" change\";\n }\n return \"Made \" + size + \" changes\";\n };\n renderComment = function(comment) {\n var _ref;\n if (comment.delete_comment_date || comment.delete_comment_user) {\n return templateDeletedComment({\n deleteCommentDate: moment(comment.delete_comment_date).format(\"DD MMM YYYY HH:mm\"),\n deleteCommentUser: comment.delete_comment_user.name,\n deleteComment: comment.comment_html,\n activityId: comment.id,\n canRestoreComment: comment.delete_comment_user.pk === $scope.user.id || $scope.project.my_permissions.indexOf(\"modify_project\") > -1\n });\n }\n return templateActivity({\n avatar: getUserAvatar(comment.user.pk),\n userFullName: comment.user.name,\n creationDate: moment(comment.created_at).format(\"DD MMM YYYY HH:mm\"),\n comment: comment.comment_html,\n changesText: renderChangesHelperText(comment),\n changes: renderChangeEntries(comment, false),\n mode: \"comment\",\n deleteCommentDate: comment.delete_comment_date ? moment(comment.delete_comment_date).format(\"DD MMM YYYY HH:mm\") : void 0,\n deleteCommentUser: ((_ref = comment.delete_comment_user) != null ? _ref.name : void 0) ? comment.delete_comment_user.name : void 0,\n activityId: comment.id,\n canDeleteComment: comment.user.pk === $scope.user.id || $scope.project.my_permissions.indexOf(\"modify_project\") > -1\n });\n };\n renderChange = function(change) {\n var _ref;\n return templateActivity({\n avatar: getUserAvatar(change.user.pk),\n userFullName: change.user.name,\n creationDate: moment(change.created_at).format(\"DD MMM YYYY HH:mm\"),\n comment: change.comment_html,\n changes: renderChangeEntries(change, false),\n changesText: \"\",\n mode: \"activity\",\n deleteCommentDate: change.delete_comment_date ? moment(change.delete_comment_date).format(\"DD MMM YYYY HH:mm\") : void 0,\n deleteCommentUser: ((_ref = change.delete_comment_user) != null ? _ref.name : void 0) ? change.delete_comment_user.name : void 0,\n activityId: change.id\n });\n };\n renderHistory = function(entries, totalEntries) {\n var showMore;\n if (entries.length === totalEntries) {\n showMore = 0;\n } else {\n showMore = totalEntries - entries.length;\n }\n return templateBaseEntries({\n entries: entries,\n showMore: showMore\n });\n };\n renderComments = function() {\n var comments, html, totalComments;\n comments = $scope.comments || [];\n totalComments = comments.length;\n if (!showAllComments) {\n comments = _.last(comments, 4);\n }\n comments = _.map(comments, function(x) {\n return renderComment(x);\n });\n html = renderHistory(comments, totalComments);\n return $el.find(\".comments-list\").html(html);\n };\n renderActivity = function() {\n var changes, html, totalChanges;\n changes = $scope.history || [];\n totalChanges = changes.length;\n if (!showAllActivity) {\n changes = _.last(changes, 4);\n }\n changes = _.map(changes, function(x) {\n return renderChange(x);\n });\n html = renderHistory(changes, totalChanges);\n return $el.find(\".changes-list\").html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(target) {\n var model, onError, onSuccess;\n $scope.$broadcast(\"markdown-editor:submit\");\n $el.find(\".comment-list\").addClass(\"activeanimation\");\n onSuccess = function() {\n return $ctrl.loadHistory(type, objectId)[\"finally\"](function() {\n return $loading.finish(target);\n });\n };\n onError = function() {\n $loading.finish(target);\n return $confirm.notify(\"error\");\n };\n model = $scope.$eval($attrs.ngModel);\n $loading.start(target);\n return $ctrl.repo.save(model).then(onSuccess, onError);\n };\n })(this));\n $scope.$watch(\"comments\", renderComments);\n $scope.$watch(\"history\", renderActivity);\n $scope.$on(\"history:reload\", function() {\n return $ctrl.loadHistory(type, objectId);\n });\n $el.on(\"click\", \".add-comment a.button-green\", debounce(2000, function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return save(target);\n }));\n $el.on(\"click\", \".show-more\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n if (target.parent().is(\".changes-list\")) {\n showAllActivity = !showAllActivity;\n return renderActivity();\n } else {\n showAllComments = !showAllComments;\n return renderComments();\n }\n });\n $el.on(\"click\", \".show-deleted-comment\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.parents('.activity-single').find('.hide-deleted-comment').show();\n target.parents('.activity-single').find('.show-deleted-comment').hide();\n return target.parents('.activity-single').find('.comment-body').show();\n });\n $el.on(\"click\", \".hide-deleted-comment\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.parents('.activity-single').find('.hide-deleted-comment').hide();\n target.parents('.activity-single').find('.show-deleted-comment').show();\n return target.parents('.activity-single').find('.comment-body').hide();\n });\n $el.on(\"click\", \".changes-title\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return target.parent().find(\".change-entry\").toggleClass(\"active\");\n });\n $el.on(\"focus\", \".add-comment textarea\", function(event) {\n return $(this).addClass('active');\n });\n $el.on(\"click\", \".history-tabs li a\", function(event) {\n $el.find(\".history-tabs li a\").toggleClass(\"active\");\n return $el.find(\".history section\").toggleClass(\"hidden\");\n });\n $el.on(\"click\", \".comment-delete\", debounce(2000, function(event) {\n var activityId, target;\n target = angular.element(event.currentTarget);\n activityId = target.data('activity-id');\n return $ctrl.deleteComment(type, objectId, activityId);\n }));\n $el.on(\"click\", \".comment-restore\", debounce(2000, function(event) {\n var activityId, target;\n target = angular.element(event.currentTarget);\n activityId = target.data('activity-id');\n return $ctrl.undeleteComment(type, objectId, activityId);\n }));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n templateFn = function($el, $attrs) {\n return templateBase({\n ngmodel: $attrs.ngModel,\n type: $attrs.type,\n mode: $attrs.mode\n });\n };\n return {\n controller: HistoryController,\n template: templateFn,\n restrict: \"AE\",\n link: link\n };\n };\n\n module.directive(\"tgHistory\", [\"$log\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", HistoryDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/importer.coffee\n */\n\n(function() {\n var ImportProjectButtonDirective, module;\n\n module = angular.module(\"taigaCommon\");\n\n ImportProjectButtonDirective = function($rs, $confirm, $location, $navUrls) {\n var link;\n link = function($scope, $el, $attrs) {\n $el.on(\"click\", \".import-project-button\", function(event) {\n event.preventDefault();\n $el.find(\"input.import-file\").val(\"\");\n return $el.find(\"input.import-file\").trigger(\"click\");\n });\n return $el.on(\"change\", \"input.import-file\", function(event) {\n var file, loader, onError, onSuccess;\n event.preventDefault();\n file = event.target.files[0];\n if (!file) {\n return;\n }\n loader = $confirm.loader(\"Uploading dump file\");\n onSuccess = function(result) {\n var ctx, message, title;\n loader.stop();\n if (result.status === 202) {\n title = \"Our Oompa Loompas are importing your project\";\n message = \"This process could take a few minutes
    We will send you an email when ready\";\n return $confirm.success(title, message);\n } else {\n ctx = {\n project: result.data.slug\n };\n $location.path($navUrls.resolve(\"project-admin-project-profile-details\", ctx));\n return $confirm.notify(\"success\", \"Your project has been imported successfuly.\");\n }\n };\n onError = function(result) {\n var errorMsg, _ref;\n loader.stop();\n console.log(\"Error\", result);\n errorMsg = \"Our oompa loompas have some problems importing your dump data. Please try again. \";\n if (result.status === 429) {\n errorMsg = \"Sorry, our oompa loompas are very busy right now. Please try again in a few minutes. \";\n } else if ((_ref = result.data) != null ? _ref._error_message : void 0) {\n errorMsg = \"Our oompa loompas have some problems importing your dump data: \" + result.data._error_message;\n }\n return $confirm.notify(\"error\", errorMsg);\n };\n loader.start();\n return $rs.projects[\"import\"](file, loader.update).then(onSuccess, onError);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgImportProjectButton\", [\"$tgResources\", \"$tgConfirm\", \"$location\", \"$tgNavUrls\", ImportProjectButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/lightboxes.coffee\n */\n\n(function() {\n var AssignedToLightboxDirective, BlockLightboxDirective, BlockingMessageInputDirective, CreateBulkUserstoriesDirective, CreateEditUserstoryDirective, LightboxDirective, LightboxKeyboardNavigationService, LightboxService, NotionButtonDirective, NotionLightboxDirective, WatchersLightboxDirective, bindOnce, debounce, module, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n module = angular.module(\"taigaCommon\");\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n debounce = this.taiga.debounce;\n\n LightboxService = (function(_super) {\n __extends(LightboxService, _super);\n\n function LightboxService(animationFrame) {\n this.animationFrame = animationFrame;\n }\n\n LightboxService.prototype.open = function($el) {\n var docEl, lightboxContent;\n lightboxContent = $el.children().not(\".close\");\n lightboxContent.hide();\n $el.css('display', 'flex');\n $el.find('input,textarea').first().focus();\n this.animationFrame.add((function(_this) {\n return function() {\n $el.addClass(\"open\");\n return lightboxContent.show();\n };\n })(this));\n docEl = angular.element(document);\n return docEl.on(\"keydown.lightbox\", (function(_this) {\n return function(e) {\n var code;\n code = e.keyCode ? e.keyCode : e.which;\n if (code === 27) {\n return _this.close($el);\n }\n };\n })(this));\n };\n\n LightboxService.prototype.close = function($el) {\n var docEl;\n docEl = angular.element(document);\n docEl.off(\".lightbox\");\n docEl.off(\".keyboard-navigation\");\n $el.one(\"transitionend\", (function(_this) {\n return function() {\n $el.removeAttr('style');\n return $el.removeClass(\"open\").removeClass('close');\n };\n })(this));\n return $el.addClass('close');\n };\n\n LightboxService.prototype.closeAll = function() {\n var docEl, lightboxEl, _i, _len, _ref, _results;\n docEl = angular.element(document);\n _ref = docEl.find(\".lightbox.open\");\n _results = [];\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n lightboxEl = _ref[_i];\n _results.push(this.close($(lightboxEl)));\n }\n return _results;\n };\n\n return LightboxService;\n\n })(taiga.Service);\n\n module.service(\"lightboxService\", [\"animationFrame\", LightboxService]);\n\n LightboxKeyboardNavigationService = (function(_super) {\n __extends(LightboxKeyboardNavigationService, _super);\n\n function LightboxKeyboardNavigationService() {\n return LightboxKeyboardNavigationService.__super__.constructor.apply(this, arguments);\n }\n\n LightboxKeyboardNavigationService.prototype.stop = function() {\n var docEl;\n docEl = angular.element(document);\n return docEl.off(\".keyboard-navigation\");\n };\n\n LightboxKeyboardNavigationService.prototype.dispatch = function($el, code) {\n var activeElement, next, prev;\n activeElement = $el.find(\".active\");\n if (code === 13) {\n return activeElement.trigger(\"click\");\n } else if (code === 40) {\n if (!activeElement.length) {\n return $el.find('.watcher-single:first').addClass('active');\n } else {\n next = activeElement.next('.watcher-single');\n if (next.length) {\n activeElement.removeClass('active');\n return next.addClass('active');\n }\n }\n } else if (code === 38) {\n if (!activeElement.length) {\n return $el.find('.watcher-single:last').addClass('active');\n } else {\n prev = activeElement.prev('.watcher-single');\n if (prev.length) {\n activeElement.removeClass('active');\n return prev.addClass('active');\n }\n }\n }\n };\n\n LightboxKeyboardNavigationService.prototype.init = function($el) {\n var docEl;\n this.stop();\n docEl = angular.element(document);\n return docEl.on(\"keydown.keyboard-navigation\", (function(_this) {\n return function(event) {\n var code;\n code = event.keyCode ? event.keyCode : event.which;\n if (code === 40 || code === 38 || code === 13) {\n event.preventDefault();\n return _this.dispatch($el, code);\n }\n };\n })(this));\n };\n\n return LightboxKeyboardNavigationService;\n\n })(taiga.Service);\n\n module.service(\"lightboxKeyboardNavigationService\", LightboxKeyboardNavigationService);\n\n LightboxDirective = function(lightboxService) {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n };\n return {\n restrict: \"C\",\n link: link\n };\n };\n\n module.directive(\"lightbox\", [\"lightboxService\", LightboxDirective]);\n\n BlockLightboxDirective = function($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var block, unblock;\n $el.find(\"h2.title\").text($attrs.title);\n unblock = $qqueue.bindAdd((function(_this) {\n return function(item, finishCallback) {\n var promise;\n promise = $tgrepo.save(item);\n promise.then(function() {\n $confirm.notify(\"success\");\n $rootscope.$broadcast(\"history:reload\");\n $model.$setViewValue(item);\n return finishCallback();\n });\n promise.then(null, function() {\n $confirm.notify(\"error\");\n item.revert();\n return $model.$setViewValue(item);\n });\n promise[\"finally\"](function() {\n return finishCallback();\n });\n return promise;\n };\n })(this));\n block = $qqueue.bindAdd((function(_this) {\n return function(item) {\n var promise;\n $model.$setViewValue(item);\n $loading.start($el.find(\".button-green\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n $confirm.notify(\"error\");\n item.revert();\n return $model.$setViewValue(item);\n });\n return promise[\"finally\"](function() {\n $loading.finish($el.find(\".button-green\"));\n return lightboxService.close($el);\n });\n };\n })(this));\n $scope.$on(\"block\", function() {\n $el.find(\".reason\").val($model.$modelValue.blocked_note);\n return lightboxService.open($el);\n });\n $scope.$on(\"unblock\", (function(_this) {\n return function(event, model, finishCallback) {\n var item;\n item = $model.$modelValue.clone();\n item.is_blocked = false;\n item.blocked_note = \"\";\n return unblock(item, finishCallback);\n };\n })(this));\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return $el.on(\"click\", \".button-green\", function(event) {\n var item;\n event.preventDefault();\n item = $model.$modelValue.clone();\n item.is_blocked = true;\n item.blocked_note = $el.find(\".reason\").val();\n return block(item);\n });\n };\n return {\n templateUrl: \"common/lightbox/lightbox-block.html\",\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgLbBlock\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"lightboxService\", \"$tgLoading\", \"$tgQqueue\", BlockLightboxDirective]);\n\n BlockingMessageInputDirective = function($log, $template) {\n var link, template, templateFn;\n template = $template.get(\"common/lightbox/lightbox-blocking-message-input.html\", true);\n link = function($scope, $el, $attrs, $model) {\n if (!$attrs.watch) {\n return $log.error(\"No watch attribute on tg-blocking-message-input directive\");\n }\n return $scope.$watch($attrs.watch, function(value) {\n if (value === !void 0 && value === true) {\n return $el.find(\".blocked-note\").removeClass(\"hidden\");\n } else {\n return $el.find(\".blocked-note\").addClass(\"hidden\");\n }\n });\n };\n templateFn = function($el, $attrs) {\n return template({\n ngmodel: $attrs.ngModel\n });\n };\n return {\n template: templateFn,\n link: link,\n require: \"ngModel\",\n restrict: \"EA\"\n };\n };\n\n module.directive(\"tgBlockingMessageInput\", [\"$log\", \"$tgTemplate\", BlockingMessageInputDirective]);\n\n CreateEditUserstoryDirective = function($repo, $model, $rs, $rootScope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.isNew = true;\n $scope.$on(\"usform:new\", function(ctx, projectId, status, statusList) {\n $scope.isNew = true;\n $scope.usStatusList = statusList;\n $scope.us = $model.make_model(\"userstories\", {\n project: projectId,\n points: {},\n status: status,\n is_archived: false,\n tags: []\n });\n $el.find(\".button-green\").html(\"Create\");\n $el.find(\".title\").html(\"New user story \");\n $el.find(\".tag-input\").val(\"\");\n $el.find(\".blocked-note\").addClass(\"hidden\");\n $el.find(\"label.blocked\").removeClass(\"selected\");\n $el.find(\"label.team-requirement\").removeClass(\"selected\");\n $el.find(\"label.client-requirement\").removeClass(\"selected\");\n return lightboxService.open($el);\n });\n $scope.$on(\"usform:edit\", function(ctx, us) {\n $scope.us = us;\n $scope.isNew = false;\n $el.find(\".button-green\").html(\"Save\");\n $el.find(\".title\").html(\"Edit user story \");\n $el.find(\".tag-input\").val(\"\");\n if (us.is_blocked) {\n $el.find(\".blocked-note\").removeClass(\"hidden\");\n $el.find(\"label.blocked\").addClass(\"selected\");\n } else {\n $el.find(\".blocked-note\").addClass(\"hidden\");\n $el.find(\"label.blocked\").removeClass(\"selected\");\n }\n if (us.team_requirement) {\n $el.find(\"label.team-requirement\").addClass(\"selected\");\n } else {\n $el.find(\"label.team-requirement\").removeClass(\"selected\");\n }\n if (us.client_requirement) {\n $el.find(\"label.client-requirement\").addClass(\"selected\");\n } else {\n $el.find(\"label.client-requirement\").removeClass(\"selected\");\n }\n return lightboxService.open($el);\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n if ($scope.isNew) {\n promise = $repo.create(\"userstories\", $scope.us);\n broadcastEvent = \"usform:new:success\";\n } else {\n promise = $repo.save($scope.us);\n broadcastEvent = \"usform:edit:success\";\n }\n promise.then(function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n return $rootScope.$broadcast(broadcastEvent, data);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n $scope.$apply(function() {\n return $scope.us.revert();\n });\n return lightboxService.close($el);\n });\n $el.keydown(function(event) {\n var code;\n code = event.keyCode ? event.keyCode : event.which;\n if (code === 27) {\n lightboxService.close($el);\n return $scope.$apply(function() {\n return $scope.us.revert();\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateEditUserstory\", [\"$tgRepo\", \"$tgModel\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateEditUserstoryDirective]);\n\n CreateBulkUserstoriesDirective = function($repo, $rs, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.$on(\"usform:bulk\", function(ctx, projectId, status) {\n $scope[\"new\"] = {\n projectId: projectId,\n statusId: status,\n bulk: \"\"\n };\n return lightboxService.open($el);\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley({\n onlyOneErrorElement: true\n });\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $rs.userstories.bulkCreate($scope[\"new\"].projectId, $scope[\"new\"].statusId, $scope[\"new\"].bulk);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"usform:bulk:success\", result);\n return lightboxService.close($el);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateBulkUserstories\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateBulkUserstoriesDirective]);\n\n AssignedToLightboxDirective = function(lightboxService, lightboxKeyboardNavigationService, $template) {\n var link;\n link = function($scope, $el, $attrs) {\n var closeLightbox, filterUsers, normalizeString, render, selectedItem, selectedUser, usersTemplate;\n selectedUser = null;\n selectedItem = null;\n usersTemplate = $template.get(\"common/lightbox/lightbox-assigned-to-users.html\", true);\n normalizeString = function(string) {\n var normalizedString;\n normalizedString = string;\n normalizedString = normalizedString.replace(\"Á\", \"A\").replace(\"Ä\", \"A\").replace(\"À\", \"A\");\n normalizedString = normalizedString.replace(\"É\", \"E\").replace(\"Ë\", \"E\").replace(\"È\", \"E\");\n normalizedString = normalizedString.replace(\"Í\", \"I\").replace(\"Ï\", \"I\").replace(\"Ì\", \"I\");\n normalizedString = normalizedString.replace(\"Ó\", \"O\").replace(\"Ö\", \"O\").replace(\"Ò\", \"O\");\n normalizedString = normalizedString.replace(\"Ú\", \"U\").replace(\"Ü\", \"U\").replace(\"Ù\", \"U\");\n return normalizedString;\n };\n filterUsers = function(text, user) {\n var username;\n username = user.full_name_display.toUpperCase();\n username = normalizeString(username);\n text = text.toUpperCase();\n text = normalizeString(text);\n return _.contains(username, text);\n };\n render = function(selected, text) {\n var ctx, html, users;\n $el.find(\"input\").focus();\n users = _.clone($scope.activeUsers, true);\n if (selected != null) {\n users = _.reject(users, {\n \"id\": selected.id\n });\n }\n if (text != null) {\n users = _.filter(users, _.partial(filterUsers, text));\n }\n ctx = {\n selected: selected,\n users: _.first(users, 5),\n showMore: users.length > 5\n };\n html = usersTemplate(ctx);\n $el.find(\"div.watchers\").html(html);\n return lightboxKeyboardNavigationService.init($el);\n };\n closeLightbox = function() {\n lightboxKeyboardNavigationService.stop();\n return lightboxService.close($el);\n };\n $scope.$on(\"assigned-to:add\", function(ctx, item) {\n var assignedToId;\n selectedItem = item;\n assignedToId = item.assigned_to;\n selectedUser = $scope.usersById[assignedToId];\n render(selectedUser);\n lightboxService.open($el);\n return $el.find('input').focus();\n });\n $scope.$watch(\"usersSearch\", function(searchingText) {\n if (searchingText != null) {\n return render(selectedUser, searchingText);\n }\n });\n $el.on(\"click\", \".watcher-single\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n closeLightbox();\n return $scope.$apply(function() {\n $scope.$broadcast(\"assigned-to:added\", target.data(\"user-id\"), selectedItem);\n return $scope.usersSearch = null;\n });\n });\n $el.on(\"click\", \".remove-assigned-to\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n closeLightbox();\n return $scope.$apply(function() {\n $scope.usersSearch = null;\n return $scope.$broadcast(\"assigned-to:added\", null, selectedItem);\n });\n });\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n closeLightbox();\n return $scope.$apply(function() {\n return $scope.usersSearch = null;\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"common/lightbox/lightbox-assigned-to.html\",\n link: link\n };\n };\n\n module.directive(\"tgLbAssignedto\", [\"lightboxService\", \"lightboxKeyboardNavigationService\", \"$tgTemplate\", AssignedToLightboxDirective]);\n\n WatchersLightboxDirective = function($repo, lightboxService, lightboxKeyboardNavigationService) {\n var link;\n link = function($scope, $el, $attrs) {\n var closeLightbox, getFilteredUsers, render, selectedItem;\n selectedItem = null;\n getFilteredUsers = function(text) {\n var users, _filterUsers;\n if (text == null) {\n text = \"\";\n }\n _filterUsers = function(text, user) {\n var username;\n if (selectedItem && _.find(selectedItem.watchers, function(x) {\n return x === user.id;\n })) {\n return false;\n }\n username = user.full_name_display.toUpperCase();\n text = text.toUpperCase();\n return _.contains(username, text);\n };\n users = _.clone($scope.activeUsers, true);\n users = _.filter(users, _.partial(_filterUsers, text));\n return users;\n };\n render = function(users) {\n var ctx, html;\n $el.find(\"input\").focus();\n ctx = {\n selected: false,\n users: _.first(users, 5),\n showMore: users.length > 5\n };\n html = usersTemplate(ctx);\n return $el.find(\"div.watchers\").html(html);\n };\n closeLightbox = function() {\n lightboxKeyboardNavigationService.stop();\n return lightboxService.close($el);\n };\n $scope.$on(\"watcher:add\", function(ctx, item) {\n var users;\n selectedItem = item;\n users = getFilteredUsers();\n render(users);\n lightboxService.open($el);\n return lightboxKeyboardNavigationService.init($el);\n });\n $scope.$watch(\"usersSearch\", function(searchingText) {\n var users;\n if (searchingText == null) {\n return;\n }\n users = getFilteredUsers(searchingText);\n return render(users);\n });\n $el.on(\"click\", \".watcher-single\", debounce(2000, function(event) {\n var target;\n closeLightbox();\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return $scope.$apply(function() {\n $scope.usersSearch = null;\n return $scope.$broadcast(\"watcher:added\", target.data(\"user-id\"));\n });\n }));\n $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n closeLightbox();\n return $scope.$apply(function() {\n return $scope.usersSearch = null;\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"common/lightbox/lightbox-users.html\",\n link: link\n };\n };\n\n module.directive(\"tgLbWatchers\", [\"$tgRepo\", \"lightboxService\", \"lightboxKeyboardNavigationService\", WatchersLightboxDirective]);\n\n NotionLightboxDirective = function(lightboxService) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $scope.$on(\"notion:open\", function(event, lightboxId) {\n if ($el.attr(\"id\") === lightboxId) {\n return lightboxService.open($el);\n }\n });\n $el.on(\"click\", \".button-green\", function(event) {\n return lightboxService.close($el);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbNotion\", [\"lightboxService\", NotionLightboxDirective]);\n\n NotionButtonDirective = function($log, $rootScope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n if ($attrs.tgLbNotionButton == null) {\n return $log.error(\"NotionButtonDirective: the directive need the id of the notion lightbox\");\n }\n $el.on(\"click\", function() {\n return $rootScope.$broadcast(\"notion:open\", $attrs.tgLbNotionButton);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbNotionButton\", [\"$log\", \"$rootScope\", NotionButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n * Copyright (C) 2014 Juan Francisco Alcántara \n * Copyright (C) 2014 Alejandro Alonso \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/loader.coffee\n */\n\n(function() {\n var Loader, LoaderDirective, module, sizeFormat, taiga, timeout;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaCommon\");\n\n LoaderDirective = function(tgLoader, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n tgLoader.onStart(function() {\n $(document.body).addClass(\"loader-active\");\n return $el.addClass(\"active\");\n });\n tgLoader.onEnd(function() {\n $(document.body).removeClass(\"loader-active\");\n return $el.removeClass(\"active\");\n });\n $rootscope.$on(\"$routeChangeSuccess\", function(e) {\n return tgLoader.startCurrentPageLoader();\n });\n return $rootscope.$on(\"$locationChangeSuccess\", function(e) {\n return tgLoader.reset();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLoader\", [\"tgLoader\", \"$rootScope\", LoaderDirective]);\n\n Loader = function() {\n var config, defaultConfig, forceDisabled;\n forceDisabled = false;\n defaultConfig = {\n enabled: false,\n minTime: 300\n };\n config = _.merge({}, defaultConfig);\n this.add = function() {\n return function() {\n if (!forceDisabled) {\n return config.enabled = true;\n }\n };\n };\n this.$get = [\n \"$rootScope\", function($rootscope) {\n var pageLoaded, reset, start, startLoadTime;\n startLoadTime = 0;\n reset = function() {\n return config = _.merge({}, defaultConfig);\n };\n pageLoaded = function(force) {\n var diff, endTime, timeoutValue;\n if (force == null) {\n force = false;\n }\n if (startLoadTime) {\n timeoutValue = 0;\n if (!force) {\n endTime = new Date().getTime();\n diff = endTime - startLoadTime;\n if (diff < config.minTime) {\n timeoutValue = config.minTime - diff;\n }\n }\n return timeout(timeoutValue, function() {\n return $rootscope.$broadcast(\"loader:end\");\n });\n }\n };\n start = function() {\n startLoadTime = new Date().getTime();\n return $rootscope.$broadcast(\"loader:start\");\n };\n return {\n reset: reset,\n pageLoaded: pageLoaded,\n start: start,\n startCurrentPageLoader: function() {\n if (config.enabled) {\n return start();\n }\n },\n onStart: function(fn) {\n return $rootscope.$on(\"loader:start\", fn);\n },\n onEnd: function(fn) {\n return $rootscope.$on(\"loader:end\", fn);\n },\n preventLoading: function() {\n return forceDisabled = true;\n },\n disablePreventLoading: function() {\n return forceDisabled = false;\n }\n };\n }\n ];\n };\n\n module.provider(\"tgLoader\", [Loader]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/lightboxes.coffee\n */\n\n(function() {\n var TgLoadingService, module,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n module = angular.module(\"taigaCommon\");\n\n TgLoadingService = (function(_super) {\n __extends(TgLoadingService, _super);\n\n function TgLoadingService() {\n return TgLoadingService.__super__.constructor.apply(this, arguments);\n }\n\n TgLoadingService.prototype.start = function(target) {\n if (!target.hasClass('loading')) {\n target.data('loading-old-content', target.html());\n target.addClass('loading');\n return target.html(\"loading...\");\n }\n };\n\n TgLoadingService.prototype.finish = function(target) {\n var oldContent;\n if (target.hasClass('loading')) {\n oldContent = target.data('loading-old-content');\n target.data('loading-old-content', null);\n target.html(oldContent);\n return target.removeClass('loading');\n }\n };\n\n return TgLoadingService;\n\n })(taiga.Service);\n\n module.service(\"$tgLoading\", TgLoadingService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/popovers.coffee\n */\n\n(function() {\n var RelatedTaskStatusDirective, UsStatusDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaCommon\");\n\n UsStatusDirective = function($repo, $template) {\n\n /*\n Print the status of a US and a popover to change it.\n - tg-us-status: The user story\n - on-update: Method call after US is updated\n \n Example:\n \n div.status(tg-us-status=\"us\" on-update=\"ctrl.loadSprintState()\")\n a.us-status(href=\"\", title=\"Status Name\")\n \n NOTE: This directive need 'usStatusById' and 'project'.\n */\n var link, template;\n template = $template.get(\"common/popover/popover-us-status.html\", true);\n link = function($scope, $el, $attrs) {\n var $ctrl, render, us;\n $ctrl = $el.controller();\n render = function(us) {\n var usStatusById, usStatusDom, usStatusDomParent;\n usStatusDomParent = $el.find(\".us-status\");\n usStatusDom = $el.find(\".us-status .us-status-bind\");\n usStatusById = $scope.usStatusById;\n if (usStatusById[us.status]) {\n usStatusDom.text(usStatusById[us.status].name);\n return usStatusDomParent.css(\"color\", usStatusById[us.status].color);\n }\n };\n $el.on(\"click\", \".us-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", debounce(2000, function(event) {\n var target, us;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n us = $scope.$eval($attrs.tgUsStatus);\n us.status = target.data(\"status-id\");\n render(us);\n $el.find(\".pop-status\").popover().close();\n return $scope.$apply(function() {\n return $repo.save(us).then(function() {\n return $scope.$eval($attrs.onUpdate);\n });\n });\n }));\n $scope.$on(\"userstories:loaded\", function() {\n return render($scope.$eval($attrs.tgUsStatus));\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n us = $scope.$eval($attrs.tgUsStatus);\n render(us);\n return bindOnce($scope, \"project\", function(project) {\n var html;\n html = template({\n \"statuses\": project.us_statuses\n });\n $el.append(html);\n if ($scope.project.my_permissions.indexOf(\"modify_us\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUsStatus\", [\"$tgRepo\", \"$tgTemplate\", UsStatusDirective]);\n\n RelatedTaskStatusDirective = function($repo, $template) {\n\n /*\n Print the status of a related task and a popover to change it.\n - tg-related-task-status: The related task\n - on-update: Method call after US is updated\n \n Example:\n \n div.status(tg-related-task-status=\"task\" on-update=\"ctrl.loadSprintState()\")\n a.task-status(href=\"\", title=\"Status Name\")\n \n NOTE: This directive need 'taskStatusById' and 'project'.\n */\n var link, selectionTemplate, updateTaskStatus;\n selectionTemplate = $template.get(\"common/popover/popover-related-task-status.html\", true);\n updateTaskStatus = function($el, task, taskStatusById) {\n var taskStatusDom, taskStatusDomParent;\n taskStatusDomParent = $el.find(\".us-status\");\n taskStatusDom = $el.find(\".task-status .task-status-bind\");\n if (taskStatusById[task.status]) {\n taskStatusDom.text(taskStatusById[task.status].name);\n return taskStatusDomParent.css('color', taskStatusById[task.status].color);\n }\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, autoSave, notAutoSave, task;\n $ctrl = $el.controller();\n task = $scope.$eval($attrs.tgRelatedTaskStatus);\n notAutoSave = $scope.$eval($attrs.notAutoSave);\n autoSave = !notAutoSave;\n $el.on(\"click\", \".task-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", debounce(2000, function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n task.status = target.data(\"status-id\");\n $el.find(\".pop-status\").popover().close();\n updateTaskStatus($el, task, $scope.taskStatusById);\n if (autoSave) {\n return $scope.$apply(function() {\n return $repo.save(task).then(function() {\n $scope.$eval($attrs.onUpdate);\n return $scope.$emit(\"related-tasks:status-changed\");\n });\n });\n }\n }));\n taiga.bindOnce($scope, \"project\", function(project) {\n $el.append(selectionTemplate({\n 'statuses': project.task_statuses\n }));\n updateTaskStatus($el, task, $scope.taskStatusById);\n if (project.my_permissions.indexOf(\"modify_task\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRelatedTaskStatus\", [\"$tgRepo\", \"$tgTemplate\", RelatedTaskStatusDirective]);\n\n $.fn.popover = function() {\n var $el, close, closeAll, closePopover, isVisible, open;\n $el = this;\n isVisible = (function(_this) {\n return function() {\n var docViewBottom, docViewLeft, docViewRight, docViewTop, docViewWidth, elemBottom, elemLeft, elemRight, elemTop, elemWidth;\n $el.css({\n \"display\": \"block\",\n \"visibility\": \"hidden\"\n });\n docViewTop = $(window).scrollTop();\n docViewBottom = docViewTop + $(window).height();\n docViewWidth = $(window).width();\n docViewRight = docViewWidth;\n docViewLeft = 0;\n elemTop = $el.offset().top;\n elemBottom = elemTop + $el.height();\n elemWidth = $el.width();\n elemLeft = $el.offset().left;\n elemRight = $el.offset().left + elemWidth;\n $el.css({\n \"display\": \"none\",\n \"visibility\": \"visible\"\n });\n return (elemBottom <= docViewBottom) && (elemTop >= docViewTop) && (elemLeft >= docViewLeft) && (elemRight <= docViewRight);\n };\n })(this);\n closePopover = (function(_this) {\n return function(onClose) {\n if (onClose) {\n onClose.call($el);\n }\n $el.fadeOut(function() {\n return $el.removeClass(\"active\").removeClass(\"fix\");\n });\n return $el.off(\"popup:close\");\n };\n })(this);\n closeAll = (function(_this) {\n return function() {\n return $(\".popover.active\").each(function() {\n return $(this).trigger(\"popup:close\");\n });\n };\n })(this);\n open = (function(_this) {\n return function(onClose) {\n if ($el.hasClass(\"active\")) {\n return close();\n } else {\n closeAll();\n if (!isVisible()) {\n $el.addClass(\"fix\");\n }\n $el.fadeIn(function() {\n $el.addClass(\"active\");\n $(document.body).off(\"popover\");\n return $(document.body).one(\"click.popover\", function() {\n return closeAll();\n });\n });\n return $el.on(\"popup:close\", function(e) {\n return closePopover(onClose);\n });\n }\n };\n })(this);\n close = (function(_this) {\n return function() {\n return $el.trigger(\"popup:close\");\n };\n })(this);\n return {\n open: open,\n close: close,\n closeAll: closeAll\n };\n };\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/raven-logger.coffee\n */\n\n(function() {\n var ExceptionHandlerFactory, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaCommon\");\n\n ExceptionHandlerFactory = function($log, config) {\n var ravenConfig;\n this.config = config;\n ravenConfig = this.config.get(\"ravenConfig\", null);\n if (ravenConfig) {\n $log.debug(\"Using the RavenJS exception handler.\");\n Raven.config(ravenConfig).install();\n return function(exception, cause) {\n $log.error.apply($log, arguments);\n return Raven.captureException(exception);\n };\n } else {\n $log.debug(\"Using the default logging exception handler.\");\n return function(exception, cause) {\n return $log.error.apply($log, arguments);\n };\n }\n };\n\n module.factory(\"$exceptionHandler\", [\"$log\", \"$tgConfig\", ExceptionHandlerFactory]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/tags.coffee\n */\n\n(function() {\n var ColorizeTagsDirective, LbTagLineDirective, TagLineDirective, TagsDirective, bindOnce, module, taiga, trim,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n TagsDirective = function() {\n var formatter, link, parser;\n formatter = function(v) {\n if (_.isArray(v)) {\n return v.join(\", \");\n }\n return \"\";\n };\n parser = function(v) {\n var result;\n if (!v) {\n return [];\n }\n result = _(v.split(\",\")).map(function(x) {\n return _.str.trim(x);\n });\n return result.value();\n };\n link = function($scope, $el, $attrs, $ctrl) {\n $ctrl.$formatters.push(formatter);\n $ctrl.$parsers.push(parser);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n require: \"ngModel\",\n link: link\n };\n };\n\n module.directive(\"tgTags\", TagsDirective);\n\n ColorizeTagsDirective = function() {\n var link, templates;\n templates = {\n backlog: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\"><%- tag.name %>\\n<% }) %>\"),\n kanban: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\" title=\\\"<%- tag.name %>\\\" />\\n<% }) %>\"),\n taskboard: _.template(\"<% _.each(tags, function(tag) { %>\\n \\\" title=\\\"<%- tag.name %>\\\" />\\n<% }) %>\")\n };\n link = function($scope, $el, $attrs, $ctrl) {\n var render;\n render = function(srcTags) {\n var html, tags, template;\n template = templates[$attrs.tgColorizeTagsType];\n srcTags.sort();\n tags = _.map(srcTags, function(tag) {\n var color;\n color = $scope.project.tags_colors[tag];\n return {\n name: tag,\n color: color\n };\n });\n html = template({\n tags: tags\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.tgColorizeTags, function(tags) {\n if (tags != null) {\n return render(tags);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgColorizeTags\", ColorizeTagsDirective);\n\n LbTagLineDirective = function($rs, $template) {\n var COMMA_KEY, ENTER_KEY, link, templateTags;\n ENTER_KEY = 13;\n COMMA_KEY = 188;\n templateTags = $template.get(\"common/tag/lb-tag-line-tags.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var addValue, deleteValue, hideSaveButton, removeInputLastCharacter, renderTags, resetInput, saveInputTag, showSaveButton;\n renderTags = function(tags, tagsColors) {\n var ctx, html;\n ctx = {\n tags: _.map(tags, function(t) {\n return {\n name: t,\n color: tagsColors[t]\n };\n })\n };\n _.map(ctx.tags, (function(_this) {\n return function(tag) {\n if (tag.color) {\n return tag.style = \"border-left: 5px solid \" + tag.color;\n }\n };\n })(this));\n html = templateTags(ctx);\n return $el.find(\"div.tags-container\").html(html);\n };\n showSaveButton = function() {\n return $el.find(\".save\").removeClass(\"hidden\");\n };\n hideSaveButton = function() {\n return $el.find(\".save\").addClass(\"hidden\");\n };\n resetInput = function() {\n $el.find(\"input\").val(\"\");\n return $el.find(\"input\").autocomplete(\"close\");\n };\n addValue = function(value) {\n var tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue, false);\n if (tags == null) {\n tags = [];\n }\n if (__indexOf.call(tags, value) < 0) {\n tags.push(value);\n }\n return $scope.$apply(function() {\n return $model.$setViewValue(tags);\n });\n };\n deleteValue = function(value) {\n var tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue, false);\n tags = _.pull(tags, value);\n return $scope.$apply(function() {\n return $model.$setViewValue(tags);\n });\n };\n saveInputTag = function() {\n var value;\n value = $el.find(\"input\").val();\n addValue(value);\n resetInput();\n return hideSaveButton();\n };\n removeInputLastCharacter = (function(_this) {\n return function(input) {\n var inputValue;\n inputValue = input.val();\n return input.val(inputValue.substring(0, inputValue.length - 1));\n };\n })(this);\n $el.on(\"keypress\", \"input\", function(event) {\n if (event.keyCode !== ENTER_KEY) {\n return;\n }\n return event.preventDefault();\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n if (event.keyCode === ENTER_KEY) {\n return saveInputTag();\n } else if (event.keyCode === COMMA_KEY) {\n removeInputLastCharacter(target);\n return saveInputTag();\n } else {\n if (target.val().length) {\n return showSaveButton();\n } else {\n return hideSaveButton();\n }\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n event.preventDefault();\n return saveInputTag();\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var target, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.siblings(\".tag-name\").text();\n return deleteValue(value);\n });\n bindOnce($scope, \"project\", function(project) {\n var positioningFunction;\n positioningFunction = function(position, elements) {\n var menu;\n menu = elements.element.element;\n menu.css(\"width\", elements.target.width);\n menu.css(\"top\", position.top);\n return menu.css(\"left\", position.left);\n };\n return $el.find(\"input\").autocomplete({\n source: _.keys(project.tags_colors),\n position: {\n my: \"left top\",\n using: positioningFunction\n },\n select: function(event, ui) {\n addValue(ui.item.value);\n return ui.item.value = \"\";\n }\n });\n });\n $scope.$watch($attrs.ngModel, function(tags) {\n var tagsColors, _ref;\n tagsColors = ((_ref = $scope.project) != null ? _ref.tags_colors : void 0) || [];\n return renderTags(tags, tagsColors);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\",\n templateUrl: \"common/tag/lb-tag-line.html\"\n };\n };\n\n module.directive(\"tgLbTagLine\", [\"$tgResources\", \"$tgTemplate\", LbTagLineDirective]);\n\n TagLineDirective = function($rootScope, $repo, $rs, $confirm, $qqueue, $template) {\n var COMMA_KEY, ENTER_KEY, ESC_KEY, link, templateTags;\n ENTER_KEY = 13;\n ESC_KEY = 27;\n COMMA_KEY = 188;\n templateTags = $template.get(\"common/tag/tags-line-tags.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var addValue, deleteValue, hideAddTagButton, hideAddTagButtonText, hideInput, hideSaveButton, isEditable, removeInputLastCharacter, renderInReadModeOnly, renderTags, resetInput, saveInputTag, showAddTagButton, showAddTagButtonText, showInput, showSaveButton;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf($attrs.requiredPerm) !== -1;\n };\n renderTags = function(tags, tagsColors) {\n var ctx, html;\n ctx = {\n tags: _.map(tags, function(t) {\n return {\n name: t,\n color: tagsColors[t]\n };\n }),\n isEditable: isEditable()\n };\n html = templateTags(ctx);\n return $el.find(\"div.tags-container\").html(html);\n };\n renderInReadModeOnly = function() {\n $el.find(\".add-tag\").remove();\n $el.find(\"input\").remove();\n return $el.find(\".save\").remove();\n };\n showAddTagButton = function() {\n return $el.find(\".add-tag\").removeClass(\"hidden\");\n };\n hideAddTagButton = function() {\n return $el.find(\".add-tag\").addClass(\"hidden\");\n };\n showAddTagButtonText = function() {\n return $el.find(\".add-tag-text\").removeClass(\"hidden\");\n };\n hideAddTagButtonText = function() {\n return $el.find(\".add-tag-text\").addClass(\"hidden\");\n };\n showSaveButton = function() {\n return $el.find(\".save\").removeClass(\"hidden\");\n };\n hideSaveButton = function() {\n return $el.find(\".save\").addClass(\"hidden\");\n };\n showInput = function() {\n return $el.find(\"input\").removeClass(\"hidden\").focus();\n };\n hideInput = function() {\n return $el.find(\"input\").addClass(\"hidden\").blur();\n };\n resetInput = function() {\n $el.find(\"input\").val(\"\");\n return $el.find(\"input\").autocomplete(\"close\");\n };\n addValue = $qqueue.bindAdd(function(value) {\n var model, onError, onSuccess, tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue.tags, false);\n if (tags == null) {\n tags = [];\n }\n if (__indexOf.call(tags, value) < 0) {\n tags.push(value);\n }\n model = $model.$modelValue.clone();\n model.tags = tags;\n $model.$setViewValue(model);\n onSuccess = function() {\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n model.revert();\n return $model.$setViewValue(model);\n };\n return $repo.save(model).then(onSuccess, onError);\n });\n deleteValue = $qqueue.bindAdd(function(value) {\n var model, onError, onSuccess, tags;\n value = trim(value.toLowerCase());\n if (value.length === 0) {\n return;\n }\n tags = _.clone($model.$modelValue.tags, false);\n tags = _.pull(tags, value);\n model = $model.$modelValue.clone();\n model.tags = tags;\n $model.$setViewValue(model);\n onSuccess = function() {\n return $rootScope.$broadcast(\"history:reload\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n model.revert();\n return $model.$setViewValue(model);\n };\n return $repo.save(model).then(onSuccess, onError);\n });\n saveInputTag = function() {\n var value;\n value = $el.find(\"input\").val();\n addValue(value);\n resetInput();\n return hideSaveButton();\n };\n removeInputLastCharacter = (function(_this) {\n return function(input) {\n var inputValue;\n inputValue = input.val();\n return input.val(inputValue.substring(0, inputValue.length - 1));\n };\n })(this);\n $el.on(\"keypress\", \"input\", function(event) {\n var _ref;\n if ((_ref = event.keyCode) !== ENTER_KEY && _ref !== ESC_KEY) {\n return;\n }\n return event.preventDefault();\n });\n $el.on(\"keyup\", \"input\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n if (event.keyCode === ENTER_KEY) {\n return saveInputTag();\n } else if (event.keyCode === COMMA_KEY) {\n removeInputLastCharacter(target);\n return saveInputTag();\n } else if (event.keyCode === ESC_KEY) {\n resetInput();\n hideInput();\n hideSaveButton();\n return showAddTagButton();\n } else {\n if (target.val().length) {\n return showSaveButton();\n } else {\n return hideSaveButton();\n }\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n event.preventDefault();\n return saveInputTag();\n });\n $el.on(\"click\", \".add-tag\", function(event) {\n event.preventDefault();\n hideAddTagButton();\n return showInput();\n });\n $el.on(\"click\", \".icon-delete\", function(event) {\n var target, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.siblings(\".tag-name\").text();\n return deleteValue(value);\n });\n bindOnce($scope, \"project\", function(project) {\n var positioningFunction;\n if (!isEditable()) {\n renderInReadModeOnly();\n return;\n }\n showAddTagButton();\n positioningFunction = function(position, elements) {\n var menu;\n menu = elements.element.element;\n menu.css(\"width\", elements.target.width);\n menu.css(\"top\", position.top);\n return menu.css(\"left\", position.left);\n };\n return $el.find(\"input\").autocomplete({\n source: _.keys(project.tags_colors),\n position: {\n my: \"left top\",\n using: positioningFunction\n },\n select: function(event, ui) {\n addValue(ui.item.value);\n return ui.item.value = \"\";\n }\n });\n });\n $scope.$watch($attrs.ngModel, function(model) {\n var tagsColors, _ref, _ref1;\n if (!model) {\n return;\n }\n if ((_ref = model.tags) != null ? _ref.length : void 0) {\n hideAddTagButtonText();\n } else {\n showAddTagButtonText();\n }\n tagsColors = ((_ref1 = $scope.project) != null ? _ref1.tags_colors : void 0) || [];\n return renderTags(model.tags, tagsColors);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\",\n templateUrl: \"common/tag/tag-line.html\"\n };\n };\n\n module.directive(\"tgTagLine\", [\"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$tgQqueue\", \"$tgTemplate\", TagLineDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/wisiwyg.coffee\n */\n\n(function() {\n var bindOnce, module, taiga, tgMarkitupDirective;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaCommon\");\n\n tgMarkitupDirective = function($rootscope, $rs, $tr, $selectedText, $template) {\n var link, previewTemplate;\n previewTemplate = $template.get(\"common/wysiwyg/wysiwyg-markitup-preview.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var closePreviewMode, element, markdownCaretPositon, markdownSettings, markdownTitle, preview, previewDomNode, removeEmptyLine, setCaretPosition;\n element = angular.element($el);\n previewDomNode = $(\"
    \", {\n \"class\": \"preview\"\n });\n closePreviewMode = function() {\n element.parents(\".markdown\").find(\".preview\").remove();\n return element.parents(\".markItUp\").show();\n };\n $scope.$on(\"markdown-editor:submit\", function() {\n return closePreviewMode();\n });\n preview = function() {\n var markItUpDomNode, markdownDomNode;\n markdownDomNode = element.parents(\".markdown\");\n markItUpDomNode = element.parents(\".markItUp\");\n return $rs.mdrender.render($scope.projectId, $model.$modelValue).then(function(data) {\n var markdown;\n markdownDomNode.append(previewTemplate({\n data: data.data\n }));\n markItUpDomNode.hide();\n markdown = element.closest(\".markdown\");\n return markdown.on(\"mouseup.preview\", \".preview\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.target);\n if (!target.is('a') && $selectedText.get().length) {\n return;\n }\n markdown.off(\".preview\");\n return closePreviewMode();\n });\n });\n };\n markdownCaretPositon = false;\n setCaretPosition = function(elm, caretPos) {\n var range;\n if (elm.createTextRange) {\n range = elm.createTextRange();\n range.move(\"character\", caretPos);\n return range.select();\n } else if (elm.selectionStart) {\n elm.focus();\n return elm.setSelectionRange(caretPos, caretPos);\n }\n };\n removeEmptyLine = function(textarea, line, currentCaretPosition) {\n var lines, removedLineLength;\n lines = textarea.value.split(\"\\n\");\n removedLineLength = lines[line].length;\n lines[line] = \"\";\n textarea.value = lines.join(\"\\n\");\n return currentCaretPosition - removedLineLength + 1;\n };\n markdownSettings = {\n nameSpace: \"markdown\",\n onShiftEnter: {\n keepDefault: false,\n openWith: \"\\n\\n\"\n },\n onEnter: {\n keepDefault: false,\n replaceWith: (function(_this) {\n return function(data) {\n var breakLineAtBeginning, cursorLine, emptyListItem, lastLine, lines, match, newLineContent;\n lines = data.textarea.value.split(\"\\n\");\n cursorLine = data.textarea.value.slice(0, +(data.caretPosition - 1) + 1 || 9e9).split(\"\\n\").length;\n newLineContent = data.textarea.value.slice(data.caretPosition).split(\"\\n\")[0];\n lastLine = lines[cursorLine - 1];\n match = lastLine.match(/^(\\s*- ).*/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*)\\-\\s$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)\\-\\s/);\n if (!breakLineAtBeginning) {\n if (match) {\n return \"\\n\" + match[1];\n }\n }\n }\n }\n match = lastLine.match(/^(\\s*\\* ).*/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*\\* )$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)\\*\\s/);\n if (!breakLineAtBeginning) {\n if (match) {\n return \"\\n\" + match[1];\n }\n }\n }\n }\n match = lastLine.match(/^(\\s*)(\\d+)\\.\\s/);\n if (match) {\n emptyListItem = lastLine.match(/^(\\s*)(\\d+)\\.\\s$/);\n if (emptyListItem) {\n markdownCaretPositon = removeEmptyLine(data.textarea, lines.length - 1, data.caretPosition);\n } else {\n breakLineAtBeginning = newLineContent.match(/^(\\s*)(\\d+)\\.\\s/);\n if (!breakLineAtBeginning) {\n return \"\\n\" + (match[1] + (parseInt(match[2], 10) + 1)) + \". \";\n }\n }\n }\n return \"\\n\";\n };\n })(this),\n afterInsert: function(data) {\n var caretPosition, line, scrollRelation, totalLines;\n if (markdownCaretPositon) {\n setCaretPosition(data.textarea, markdownCaretPositon);\n caretPosition = markdownCaretPositon;\n markdownCaretPositon = false;\n } else {\n caretPosition = data.caretPosition;\n }\n totalLines = data.textarea.value.split(\"\\n\").length;\n line = data.textarea.value.slice(0, +(caretPosition - 1) + 1 || 9e9).split(\"\\n\").length;\n scrollRelation = line / totalLines;\n return $el.scrollTop((scrollRelation * $el[0].scrollHeight) - ($el.height() / 2));\n }\n },\n markupSet: [\n {\n name: $tr.t(\"markdown-editor.heading-1\"),\n key: \"1\",\n placeHolder: $tr.t(\"markdown-editor.placeholder\"),\n closeWith: function(markItUp) {\n return markdownTitle(markItUp, \"=\");\n }\n }, {\n name: $tr.t(\"markdown-editor.heading-2\"),\n key: \"2\",\n placeHolder: $tr.t(\"markdown-editor.placeholder\"),\n closeWith: function(markItUp) {\n return markdownTitle(markItUp, \"-\");\n }\n }, {\n name: $tr.t(\"markdown-editor.heading-3\"),\n key: \"3\",\n openWith: \"### \",\n placeHolder: $tr.t(\"markdown-editor.placeholder\")\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.bold\"),\n key: \"B\",\n openWith: \"**\",\n closeWith: \"**\"\n }, {\n name: $tr.t(\"markdown-editor.italic\"),\n key: \"I\",\n openWith: \"_\",\n closeWith: \"_\"\n }, {\n name: $tr.t(\"markdown-editor.strike\"),\n key: \"S\",\n openWith: \"~~\",\n closeWith: \"~~\"\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.bulleted-list\"),\n openWith: \"- \"\n }, {\n name: $tr.t(\"markdown-editor.numeric-list\"),\n openWith: function(markItUp) {\n return markItUp.line + \". \";\n }\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.picture\"),\n key: \"P\",\n replaceWith: '![[![Alternative text]!]]([![Url:!:http://]!] \"[![Title]!]\")'\n }, {\n name: $tr.t(\"markdown-editor.link\"),\n key: \"L\",\n openWith: \"[\",\n closeWith: ']([![Url:!:http://]!] \"[![Title]!]\")',\n placeHolder: $tr.t(\"markdown-editor.link-placeholder\")\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.quotes\"),\n openWith: \"> \"\n }, {\n name: $tr.t(\"markdown-editor.code-block\"),\n openWith: \"```\\n\",\n closeWith: \"\\n```\"\n }, {\n separator: \"---------------\"\n }, {\n name: $tr.t(\"markdown-editor.preview\"),\n call: preview,\n className: \"preview-icon\"\n }\n ],\n afterInsert: function(event) {\n var target;\n target = angular.element(event.textarea);\n return $model.$setViewValue(target.val());\n }\n };\n markdownTitle = function(markItUp, char) {\n var heading, i, n, _i, _ref;\n heading = \"\";\n n = $.trim(markItUp.selection || markItUp.placeHolder).length;\n for (i = _i = 0, _ref = n - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {\n heading += char;\n }\n return \"\\n\" + heading + \"\\n\";\n };\n element.markItUp(markdownSettings);\n element.on(\"keypress\", function(event) {\n return $scope.$apply();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgMarkitup\", [\"$rootScope\", \"$tgResources\", \"$tgI18n\", \"$selectedText\", \"$tgTemplate\", tgMarkitupDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/main.coffee\n */\n\n(function() {\n var BacklogFiltersDirective, bindOnce, debounceLeading, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n debounceLeading = this.taiga.debounceLeading;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogFiltersDirective = function($log, $location, $templates) {\n var link, template, templateSelected;\n template = $templates.get(\"backlog/filters.html\", true);\n templateSelected = $templates.get(\"backlog/filter-selected.html\", true);\n link = function($scope, $el, $attrs) {\n var $ctrl, initializeSelectedFilters, renderFilters, renderSelectedFilters, selectQFilter, selectedFilters, showCategories, showFilters, toggleFilterSelection;\n $ctrl = $el.closest(\".wrapper\").controller();\n selectedFilters = [];\n showFilters = function(title, type) {\n $el.find(\".filters-cats\").hide();\n $el.find(\".filter-list\").removeClass(\"hidden\");\n $el.find(\"h2.breadcrumb\").removeClass(\"hidden\");\n $el.find(\"h2 a.subfilter span.title\").html(title);\n return $el.find(\"h2 a.subfilter span.title\").prop(\"data-type\", type);\n };\n showCategories = function() {\n $el.find(\".filters-cats\").show();\n $el.find(\".filter-list\").addClass(\"hidden\");\n return $el.find(\"h2.breadcrumb\").addClass(\"hidden\");\n };\n initializeSelectedFilters = function(filters) {\n var name, val, values, _i, _len;\n showCategories();\n selectedFilters = [];\n for (name in filters) {\n values = filters[name];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n val = values[_i];\n if (val.selected) {\n selectedFilters.push(val);\n }\n }\n }\n return renderSelectedFilters();\n };\n renderSelectedFilters = function() {\n var html;\n _.map(selectedFilters, (function(_this) {\n return function(f) {\n if (f.color) {\n return f.style = \"border-left: 3px solid \" + f.color;\n }\n };\n })(this));\n html = templateSelected({\n filters: selectedFilters\n });\n return $el.find(\".filters-applied\").html(html);\n };\n renderFilters = function(filters) {\n var html;\n _.map(filters, (function(_this) {\n return function(f) {\n if (f.color) {\n return f.style = \"border-left: 3px solid \" + f.color;\n }\n };\n })(this));\n html = template({\n filters: filters\n });\n return $el.find(\".filter-list\").html(html);\n };\n toggleFilterSelection = function(type, id) {\n var currentFiltersType, filter, filters;\n filters = $scope.filters[type];\n filter = _.find(filters, {\n id: taiga.toString(id)\n });\n filter.selected = !filter.selected;\n if (filter.selected) {\n selectedFilters.push(filter);\n $scope.$apply(function() {\n $ctrl.selectFilter(type, id);\n return $ctrl.filterVisibleUserstories();\n });\n } else {\n selectedFilters = _.reject(selectedFilters, filter);\n $scope.$apply(function() {\n $ctrl.unselectFilter(type, id);\n return $ctrl.filterVisibleUserstories();\n });\n }\n renderSelectedFilters(selectedFilters);\n currentFiltersType = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (type === currentFiltersType) {\n renderFilters(_.reject(filters, \"selected\"));\n }\n return $ctrl.loadUserstories();\n };\n selectQFilter = debounceLeading(100, function(value) {\n if (value === void 0) {\n return;\n }\n if (value.length === 0) {\n $ctrl.replaceFilter(\"q\", null);\n } else {\n $ctrl.replaceFilter(\"q\", value);\n }\n return $ctrl.loadUserstories();\n });\n $scope.$watch(\"filtersQ\", selectQFilter);\n $scope.$on(\"filters:loaded\", function(ctx, filters) {\n return initializeSelectedFilters(filters);\n });\n $el.on(\"click\", \".filters-cats > ul > li > a\", function(event) {\n var tags, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n tags = $scope.filters[target.data(\"type\")];\n renderFilters(_.reject(tags, \"selected\"));\n return showFilters(target.attr(\"title\"), target.data(\"type\"));\n });\n $el.on(\"click\", \".filters-inner > .filters-step-cat > .breadcrumb > .back\", function(event) {\n event.preventDefault();\n return showCategories();\n });\n $el.on(\"click\", \".filters-applied a\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n id = target.data(\"id\");\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n return $el.on(\"click\", \".filter-list .single-filter\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n if (target.hasClass(\"active\")) {\n target.removeClass(\"active\");\n } else {\n target.addClass(\"active\");\n }\n id = target.data(\"id\");\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogFilters\", [\"$log\", \"$tgLocation\", \"$tgTemplate\", BacklogFiltersDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/lightboxes.coffee\n */\n\n(function() {\n var CreateEditSprint, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaBacklog\");\n\n CreateEditSprint = function($repo, $confirm, $rs, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, attrs) {\n var createSprint, hasErrors, remove, submit, submitButton;\n hasErrors = false;\n createSprint = true;\n $scope.sprint = {\n project: null,\n name: null,\n estimated_start: null,\n estimated_finish: null\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, newSprint, promise, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n hasErrors = true;\n $el.find(\".last-sprint-name\").addClass(\"disappear\");\n return;\n }\n hasErrors = false;\n newSprint = angular.copy($scope.sprint);\n broadcastEvent = null;\n if (createSprint) {\n newSprint.estimated_start = moment(newSprint.estimated_start).format(\"YYYY-MM-DD\");\n newSprint.estimated_finish = moment(newSprint.estimated_finish).format(\"YYYY-MM-DD\");\n promise = $repo.create(\"milestones\", newSprint);\n broadcastEvent = \"sprintform:create:success\";\n } else {\n newSprint.setAttr(\"estimated_start\", moment(newSprint.estimated_start).format(\"YYYY-MM-DD\"));\n newSprint.setAttr(\"estimated_finish\", moment(newSprint.estimated_finish).format(\"YYYY-MM-DD\"));\n promise = $repo.save(newSprint);\n broadcastEvent = \"sprintform:edit:success\";\n }\n $loading.start(submitButton);\n promise.then(function(data) {\n $loading.finish(submitButton);\n if (createSprint) {\n $scope.sprintsCounter += 1;\n }\n $rootscope.$broadcast(broadcastEvent, data);\n return lightboxService.close($el);\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"light-error\", data._error_message);\n } else if (data.__all__) {\n return $confirm.notify(\"light-error\", data.__all__[0]);\n }\n });\n };\n })(this));\n remove = function() {\n var message, title;\n title = \"Delete sprint\";\n message = $scope.sprint.name;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n finish();\n $scope.milestonesCounter -= 1;\n lightboxService.close($el);\n return $rootscope.$broadcast(\"sprintform:remove:success\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\");\n };\n return $repo.remove($scope.sprint).then(onSuccess, onError);\n };\n })(this));\n };\n $scope.$on(\"sprintform:create\", function(event, projectId) {\n var estimatedFinish, estimatedStart, lastSprint, lastSprintNameDom;\n createSprint = true;\n $scope.sprint.project = projectId;\n $scope.sprint.name = null;\n $scope.sprint.slug = null;\n lastSprint = $scope.sprints[0];\n estimatedStart = moment();\n if ($scope.sprint.estimated_start) {\n estimatedStart = moment($scope.sprint.estimated_start);\n } else if (lastSprint != null) {\n estimatedStart = moment(lastSprint.estimated_finish);\n }\n $scope.sprint.estimated_start = estimatedStart.format(\"DD MMM YYYY\");\n estimatedFinish = moment().add(2, \"weeks\");\n if ($scope.sprint.estimated_finish) {\n estimatedFinish = moment($scope.sprint.estimated_finish);\n } else if (lastSprint != null) {\n estimatedFinish = moment(lastSprint.estimated_finish).add(2, \"weeks\");\n }\n $scope.sprint.estimated_finish = estimatedFinish.format(\"DD MMM YYYY\");\n lastSprintNameDom = $el.find(\".last-sprint-name\");\n if ((lastSprint != null ? lastSprint.name : void 0) != null) {\n lastSprintNameDom.html(\" last sprint is \" + lastSprint.name + \" ;-) \");\n }\n $el.find(\".delete-sprint\").addClass(\"hidden\");\n $el.find(\".title\").text(\"New sprint\");\n $el.find(\".button-green\").text(\"Create\");\n lightboxService.open($el);\n return $el.find(\".sprint-name\").focus();\n });\n $scope.$on(\"sprintform:edit\", function(ctx, sprint) {\n createSprint = false;\n $scope.$apply(function() {\n $scope.sprint = sprint;\n $scope.sprint.estimated_start = moment($scope.sprint.estimated_start).format(\"DD MMM YYYY\");\n return $scope.sprint.estimated_finish = moment($scope.sprint.estimated_finish).format(\"DD MMM YYYY\");\n });\n $el.find(\".delete-sprint\").removeClass(\"hidden\");\n $el.find(\".title\").text(\"Edit sprint\");\n $el.find(\".button-green\").text(\"Save\");\n lightboxService.open($el);\n $el.find(\".sprint-name\").focus().select();\n return $el.find(\".last-sprint-name\").addClass(\"disappear\");\n });\n $el.on(\"keyup\", \".sprint-name\", function(event) {\n if ($el.find(\".sprint-name\").val().length > 0 || hasErrors) {\n return $el.find(\".last-sprint-name\").addClass(\"disappear\");\n } else {\n return $el.find(\".last-sprint-name\").removeClass(\"disappear\");\n }\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n $el.on(\"click\", \".delete-sprint .icon-delete\", function(event) {\n event.preventDefault();\n return remove();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateEditSprint\", [\"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateEditSprint]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/main.coffee\n */\n\n(function() {\n var BacklogController, BacklogDirective, TgBacklogProgressBarDirective, UsPointsDirective, UsRolePointsSelectorDirective, bindMethods, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, tgBacklogGraphDirective, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogController = (function(_super) {\n __extends(BacklogController, _super);\n\n BacklogController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function BacklogController(scope, rootscope, repo, confirm, rs, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Backlog\";\n this.showTags = false;\n this.activeFilters = false;\n this.excludeClosedSprints = true;\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(\"Backlog - \" + _this.scope.project.name);\n if (_this.rs.userstories.getShowTags(_this.scope.projectId)) {\n _this.showTags = true;\n return _this.scope.$broadcast(\"showTags\", _this.showTags);\n }\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n BacklogController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"usform:bulk:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"bulk create userstory on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"sprintform:create:success\", (function(_this) {\n return function() {\n _this.loadSprints();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"sprint\", \"create\", \"create sprint on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"usform:new:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.loadProjectStats();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"create userstory on backlog\", 1);\n };\n })(this));\n this.scope.$on(\"sprintform:edit:success\", (function(_this) {\n return function() {\n return _this.loadProjectStats();\n };\n })(this));\n this.scope.$on(\"sprintform:remove:success\", (function(_this) {\n return function() {\n _this.loadSprints();\n _this.loadProjectStats();\n return _this.loadUserstories();\n };\n })(this));\n this.scope.$on(\"usform:edit:success\", (function(_this) {\n return function() {\n return _this.loadUserstories();\n };\n })(this));\n this.scope.$on(\"sprint:us:move\", this.moveUs);\n this.scope.$on(\"sprint:us:moved\", this.loadSprints);\n this.scope.$on(\"sprint:us:moved\", this.loadProjectStats);\n return this.scope.$on(\"backlog:toggle-closed-sprints-visualization\", this.toggleClosedSprintsVisualization);\n };\n\n BacklogController.prototype.initializeSubscription = function() {\n var routingKey1, routingKey2;\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n _this.loadUserstories();\n return _this.loadSprints();\n };\n })(this));\n routingKey2 = \"changes.project.\" + this.scope.projectId + \".milestones\";\n return this.events.subscribe(this.scope, routingKey2, (function(_this) {\n return function(message) {\n return _this.loadSprints();\n };\n })(this));\n };\n\n BacklogController.prototype.toggleShowTags = function() {\n return this.scope.$apply((function(_this) {\n return function() {\n _this.showTags = !_this.showTags;\n return _this.rs.userstories.storeShowTags(_this.scope.projectId, _this.showTags);\n };\n })(this));\n };\n\n BacklogController.prototype.toggleActiveFilters = function() {\n return this.activeFilters = !this.activeFilters;\n };\n\n BacklogController.prototype.loadProjectStats = function() {\n return this.rs.projects.stats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n _this.scope.stats = stats;\n if (stats.total_points) {\n _this.scope.stats.completedPercentage = Math.round(100 * stats.closed_points / stats.total_points);\n } else {\n _this.scope.stats.completedPercentage = 0;\n }\n return stats;\n };\n })(this));\n };\n\n BacklogController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n BacklogController.prototype.loadSprints = function() {\n var params;\n params = {};\n if (this.excludeClosedSprints) {\n params[\"closed\"] = false;\n }\n return this.rs.sprints.list(this.scope.projectId, params).then((function(_this) {\n return function(sprints) {\n var sprint, _i, _len;\n for (_i = 0, _len = sprints.length; _i < _len; _i++) {\n sprint = sprints[_i];\n sprint.user_stories = _.sortBy(sprint.user_stories, \"sprint_order\");\n }\n _this.scope.sprints = sprints;\n _this.scope.openSprints = _.filter(sprints, function(sprint) {\n return !sprint.closed;\n }).reverse();\n _this.scope.closedSprints = _.filter(sprints, function(sprint) {\n return sprint.closed;\n });\n if (!_this.excludeClosedSprints) {\n _this.scope.totalClosedMilestones = _this.scope.closedSprints.length;\n }\n _this.scope.sprintsCounter = sprints.length;\n _this.scope.sprintsById = groupBy(sprints, function(x) {\n return x.id;\n });\n _this.rootscope.$broadcast(\"sprints:loaded\", sprints);\n return sprints;\n };\n })(this));\n };\n\n BacklogController.prototype.resetFilters = function() {\n var selectedStatuses, selectedTags;\n selectedTags = _.filter(this.scope.filters.tags, \"selected\");\n selectedStatuses = _.filter(this.scope.filters.statuses, \"selected\");\n this.scope.filtersQ = \"\";\n _.each([selectedTags, selectedStatuses], (function(_this) {\n return function(filterGrp) {\n return _.each(filterGrp, function(item) {\n var filter, filters;\n filters = _this.scope.filters[item.type];\n filter = _.find(filters, {\n id: taiga.toString(item.id)\n });\n filter.selected = false;\n return _this.unselectFilter(item.type, item.id);\n });\n };\n })(this));\n return this.loadUserstories();\n };\n\n BacklogController.prototype.loadUserstories = function() {\n var promise;\n this.scope.httpParams = this.getUrlFilters();\n this.rs.userstories.storeQueryParams(this.scope.projectId, this.scope.httpParams);\n promise = this.q.all([this.refreshTagsColors(), this.rs.userstories.listUnassigned(this.scope.projectId, this.scope.httpParams)]);\n return promise.then((function(_this) {\n return function(data) {\n var userstories;\n userstories = data[1];\n _this.scope.userstories = _.sortBy(userstories, \"backlog_order\");\n _this.generateFilters();\n _this.filterVisibleUserstories();\n _this.rootscope.$broadcast(\"filters:loaded\", _this.scope.filters);\n scopeDefer(_this.scope, function() {\n return _this.scope.$broadcast(\"userstories:loaded\");\n });\n return userstories;\n };\n })(this));\n };\n\n BacklogController.prototype.loadBacklog = function() {\n return this.q.all([this.loadProjectStats(), this.loadSprints(), this.loadUserstories()]);\n };\n\n BacklogController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.totalClosedMilestones = project.total_closed_milestones;\n _this.scope.$emit('project:loaded', project);\n _this.scope.points = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(x) {\n return x.id;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"id\");\n return project;\n };\n })(this));\n };\n\n BacklogController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.initializeSubscription();\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadBacklog();\n };\n })(this));\n };\n\n BacklogController.prototype.toggleClosedSprintsVisualization = function() {\n this.excludeClosedSprints = !this.excludeClosedSprints;\n return this.loadSprints();\n };\n\n BacklogController.prototype.filterVisibleUserstories = function() {\n var selectedStatuses, selectedTags;\n this.scope.visibleUserstories = [];\n selectedTags = _.filter(this.scope.filters.tags, \"selected\");\n selectedTags = _.map(selectedTags, \"name\");\n if (selectedTags.length === 0) {\n this.scope.visibleUserstories = _.clone(this.scope.userstories, false);\n } else {\n this.scope.visibleUserstories = _.reject(this.scope.userstories, (function(_this) {\n return function(us) {\n if (_.intersection(selectedTags, us.tags).length === 0) {\n return true;\n }\n return false;\n };\n })(this));\n }\n selectedStatuses = _.filter(this.scope.filters.statuses, \"selected\");\n selectedStatuses = _.map(selectedStatuses, \"id\");\n if (selectedStatuses.length > 0) {\n this.scope.visibleUserstories = _.reject(this.scope.visibleUserstories, (function(_this) {\n return function(us) {\n var res;\n res = _.find(selectedStatuses, function(x) {\n return x === taiga.toString(us.status);\n });\n return !res;\n };\n })(this));\n }\n return this.rs.userstories.storeQueryParams(this.scope.projectId, {\n \"status\": selectedStatuses,\n \"tags\": selectedTags,\n \"project\": this.scope.projectId,\n \"milestone\": null\n });\n };\n\n BacklogController.prototype.prepareBulkUpdateData = function(uses, field) {\n if (field == null) {\n field = \"backlog_order\";\n }\n return _.map(uses, function(x) {\n return {\n \"us_id\": x.id,\n \"order\": x[field]\n };\n });\n };\n\n BacklogController.prototype.resortUserStories = function(uses, field) {\n var index, item, items, _i, _len;\n if (field == null) {\n field = \"backlog_order\";\n }\n items = [];\n for (index = _i = 0, _len = uses.length; _i < _len; index = ++_i) {\n item = uses[index];\n item[field] = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n BacklogController.prototype.moveUs = function(ctx, usList, newUsIndex, newSprintId) {\n var data, items, newSprint, oldSprintId, project, promise, promises, us, userstories, _i, _j, _k, _len, _len1, _len2;\n oldSprintId = usList[0].milestone;\n project = usList[0].project;\n if (newSprintId === oldSprintId) {\n items = null;\n userstories = null;\n if (newSprintId === null) {\n userstories = this.scope.userstories;\n } else {\n userstories = this.scope.sprintsById[newSprintId].user_stories;\n }\n this.scope.$apply(function() {\n var args, key, r, us, _i, _len;\n for (key = _i = 0, _len = usList.length; _i < _len; key = ++_i) {\n us = usList[key];\n r = userstories.indexOf(us);\n userstories.splice(r, 1);\n }\n args = [newUsIndex, 0].concat(usList);\n return Array.prototype.splice.apply(userstories, args);\n });\n if (newSprintId === null) {\n items = this.resortUserStories(userstories, \"backlog_order\");\n data = this.prepareBulkUpdateData(items, \"backlog_order\");\n this.rs.userstories.bulkUpdateBacklogOrder(project, data).then((function(_this) {\n return function() {\n var us, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n };\n })(this));\n } else {\n items = this.resortUserStories(userstories, \"sprint_order\");\n data = this.prepareBulkUpdateData(items, \"sprint_order\");\n this.rs.userstories.bulkUpdateSprintOrder(project, data).then((function(_this) {\n return function() {\n var us, _i, _len, _results;\n _results = [];\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n };\n })(this));\n }\n return promise;\n }\n if (newSprintId === null) {\n for (_i = 0, _len = usList.length; _i < _len; _i++) {\n us = usList[_i];\n us.milestone = null;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, key, r, sprint, _j, _len1, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(_this.scope.userstories, args);\n Array.prototype.splice.apply(_this.scope.visibleUserstories, args);\n _this.filterVisibleUserstories();\n sprint = _this.scope.sprintsById[oldSprintId];\n _results = [];\n for (key = _j = 0, _len1 = usList.length; _j < _len1; key = ++_j) {\n us = usList[key];\n r = sprint.user_stories.indexOf(us);\n _results.push(sprint.user_stories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n promise = this.repo.save(us);\n promise = promise.then((function(_this) {\n return function() {\n items = _this.resortUserStories(_this.scope.userstories, \"backlog_order\");\n data = _this.prepareBulkUpdateData(items, \"backlog_order\");\n return _this.rs.userstories.bulkUpdateBacklogOrder(us.project, data).then(function() {\n return _this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId);\n });\n };\n })(this));\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n return promise;\n }\n newSprint = this.scope.sprintsById[newSprintId];\n if (oldSprintId === null) {\n for (_j = 0, _len1 = usList.length; _j < _len1; _j++) {\n us = usList[_j];\n us.milestone = newSprintId;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, key, r, _k, _len2, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(newSprint.user_stories, args);\n _results = [];\n for (key = _k = 0, _len2 = usList.length; _k < _len2; key = ++_k) {\n us = usList[key];\n r = _this.scope.visibleUserstories.indexOf(us);\n _this.scope.visibleUserstories.splice(r, 1);\n r = _this.scope.userstories.indexOf(us);\n _results.push(_this.scope.userstories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n } else {\n for (_k = 0, _len2 = usList.length; _k < _len2; _k++) {\n us = usList[_k];\n us.milestone = newSprintId;\n }\n this.scope.$apply((function(_this) {\n return function() {\n var args, oldSprint, r, _l, _len3, _results;\n args = [newUsIndex, 0].concat(usList);\n Array.prototype.splice.apply(newSprint.user_stories, args);\n _results = [];\n for (_l = 0, _len3 = usList.length; _l < _len3; _l++) {\n us = usList[_l];\n oldSprint = _this.scope.sprintsById[oldSprintId];\n r = oldSprint.user_stories.indexOf(us);\n _results.push(oldSprint.user_stories.splice(r, 1));\n }\n return _results;\n };\n })(this));\n }\n promises = _.map(usList, (function(_this) {\n return function(us) {\n return _this.repo.save(us);\n };\n })(this));\n promise = this.q.all(promises).then((function(_this) {\n return function() {\n items = _this.resortUserStories(newSprint.user_stories, \"sprint_order\");\n data = _this.prepareBulkUpdateData(items, \"sprint_order\");\n _this.rs.userstories.bulkUpdateSprintOrder(project, data).then(function() {\n return _this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId);\n });\n return _this.rs.userstories.bulkUpdateBacklogOrder(project, data).then(function() {\n var _l, _len3, _results;\n _results = [];\n for (_l = 0, _len3 = usList.length; _l < _len3; _l++) {\n us = usList[_l];\n _results.push(_this.rootscope.$broadcast(\"sprint:us:moved\", us, oldSprintId, newSprintId));\n }\n return _results;\n });\n };\n })(this));\n promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n return promise;\n };\n\n BacklogController.prototype.getUrlFilters = function() {\n return _.pick(this.location.search(), \"statuses\", \"tags\", \"q\");\n };\n\n BacklogController.prototype.generateFilters = function() {\n var isSelected, name, plainStatuses, plainTags, searchdata, urlfilters, val, value, _i, _len, _ref;\n urlfilters = this.getUrlFilters();\n if (urlfilters.q) {\n this.scope.filtersQ = urlfilters.q;\n }\n searchdata = {};\n for (name in urlfilters) {\n value = urlfilters[name];\n if (searchdata[name] == null) {\n searchdata[name] = {};\n }\n _ref = taiga.toString(value).split(\",\");\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n val = _ref[_i];\n searchdata[name][val] = true;\n }\n }\n isSelected = function(type, id) {\n if ((searchdata[type] != null) && searchdata[type][id]) {\n return true;\n }\n return false;\n };\n this.scope.filters = {};\n plainTags = _.flatten(_.filter(_.map(this.scope.userstories, \"tags\")));\n plainTags.sort();\n this.scope.filters.tags = _.map(_.countBy(plainTags), (function(_this) {\n return function(v, k) {\n var obj;\n obj = {\n id: k,\n type: \"tags\",\n name: k,\n color: _this.scope.project.tags_colors[k],\n count: v\n };\n if (isSelected(\"tags\", obj.id)) {\n obj.selected = true;\n }\n return obj;\n };\n })(this));\n plainStatuses = _.map(this.scope.userstories, \"status\");\n plainStatuses = _.filter(plainStatuses, (function(_this) {\n return function(status) {\n if (status) {\n return status;\n }\n };\n })(this));\n this.scope.filters.statuses = _.map(_.countBy(plainStatuses), (function(_this) {\n return function(v, k) {\n var obj;\n obj = {\n id: k,\n type: \"statuses\",\n name: _this.scope.usStatusById[k].name,\n color: _this.scope.usStatusById[k].color,\n count: v\n };\n if (isSelected(\"statuses\", obj.id)) {\n obj.selected = true;\n }\n return obj;\n };\n })(this));\n return this.scope.filters;\n };\n\n BacklogController.prototype.editUserStory = function(us) {\n return this.rootscope.$broadcast(\"usform:edit\", us);\n };\n\n BacklogController.prototype.deleteUserStory = function(us) {\n var message, title;\n title = \"Delete User Story\";\n message = us.subject;\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var promise;\n _this.scope.userstories = _.without(_this.scope.userstories, us);\n _this.filterVisibleUserstories();\n promise = _this.repo.remove(us);\n promise.then(function() {\n finish();\n return _this.loadBacklog();\n });\n return promise.then(null, function() {\n finish(false);\n return _this.confirm.notify(\"error\");\n });\n };\n })(this));\n };\n\n BacklogController.prototype.addNewUs = function(type) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"usform:new\", this.scope.projectId, this.scope.project.default_us_status, this.scope.usStatusList);\n case \"bulk\":\n return this.rootscope.$broadcast(\"usform:bulk\", this.scope.projectId, this.scope.project.default_us_status);\n }\n };\n\n BacklogController.prototype.addNewSprint = function() {\n return this.rootscope.$broadcast(\"sprintform:create\", this.scope.projectId);\n };\n\n return BacklogController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"BacklogController\", BacklogController);\n\n BacklogDirective = function($repo, $rootscope) {\n var doomLineTemplate, link, linkDoomLine, linkFilters, linkToolbar, showHideFilter, showHideTags;\n doomLineTemplate = _.template(\"
    Project Scope [Doomline]
    \");\n linkDoomLine = function($scope, $el, $attrs, $ctrl) {\n var addDoomLineDom, getUsItems, reloadDoomLine, removeDoomlineDom;\n reloadDoomLine = function() {\n var current_sum, element, elements, scope, stats, total_points, _i, _len, _results;\n if ($scope.stats != null) {\n removeDoomlineDom();\n elements = getUsItems();\n stats = $scope.stats;\n total_points = stats.total_points;\n current_sum = stats.assigned_points;\n _results = [];\n for (_i = 0, _len = elements.length; _i < _len; _i++) {\n element = elements[_i];\n scope = element.scope();\n if (scope.us == null) {\n continue;\n }\n current_sum += scope.us.total_points;\n if (current_sum > total_points) {\n addDoomLineDom(element);\n break;\n } else {\n _results.push(void 0);\n }\n }\n return _results;\n }\n };\n removeDoomlineDom = function() {\n return $el.find(\".doom-line\").remove();\n };\n addDoomLineDom = function(element) {\n return element != null ? element.before(doomLineTemplate({})) : void 0;\n };\n getUsItems = function() {\n var rowElements;\n rowElements = $el.find('.backlog-table-body .us-item-row');\n return _.map(rowElements, function(x) {\n return angular.element(x);\n });\n };\n $scope.$on(\"userstories:loaded\", reloadDoomLine);\n return $scope.$watch(\"stats\", reloadDoomLine);\n };\n linkToolbar = function($scope, $el, $attrs, $ctrl) {\n var moveToCurrentSprint;\n moveToCurrentSprint = function(selectedUss) {\n var extraPoints, totalExtraPoints, ussCurrent;\n ussCurrent = _($scope.userstories);\n $scope.userstories = ussCurrent.without.apply(ussCurrent, selectedUss).value();\n extraPoints = _.map(selectedUss, function(v, k) {\n return v.total_points;\n });\n totalExtraPoints = _.reduce(extraPoints, function(acc, num) {\n return acc + num;\n });\n $scope.sprints[0].user_stories = _.union($scope.sprints[0].user_stories, selectedUss);\n $scope.sprints[0].total_points += totalExtraPoints;\n $ctrl.filterVisibleUserstories();\n return $repo.saveAll(selectedUss).then(function() {\n $ctrl.loadSprints();\n return $ctrl.loadProjectStats();\n });\n };\n $el.on(\"change\", \".backlog-table-body .user-stories input:checkbox\", function(event) {\n var moveToCurrentSprintDom, selectedUsDom, target;\n target = angular.element(event.currentTarget);\n moveToCurrentSprintDom = $el.find(\"#move-to-current-sprint\");\n selectedUsDom = $el.find(\".backlog-table-body .user-stories input:checkbox:checked\");\n if (selectedUsDom.length > 0 && $scope.sprints.length > 0) {\n moveToCurrentSprintDom.show();\n } else {\n moveToCurrentSprintDom.hide();\n }\n return target.closest('.us-item-row').toggleClass('ui-multisortable-multiple');\n });\n $el.on(\"click\", \"#move-to-current-sprint\", (function(_this) {\n return function(event) {\n var ussDom, ussToMove;\n ussDom = $el.find(\".backlog-table-body .user-stories input:checkbox:checked\");\n ussToMove = _.map(ussDom, function(item) {\n var itemScope;\n itemScope = angular.element(item).scope();\n itemScope.us.milestone = $scope.sprints[0].id;\n return itemScope.us;\n });\n return $scope.$apply(_.partial(moveToCurrentSprint, ussToMove));\n };\n })(this));\n return $el.on(\"click\", \"#show-tags\", function(event) {\n event.preventDefault();\n $ctrl.toggleShowTags();\n return showHideTags($ctrl);\n });\n };\n showHideTags = function($ctrl) {\n var elm;\n elm = angular.element(\"#show-tags\");\n if ($ctrl.showTags) {\n elm.addClass(\"active\");\n return elm.find(\".text\").text(\"Hide Tags\");\n } else {\n elm.removeClass(\"active\");\n return elm.find(\".text\").text(\"Show Tags\");\n }\n };\n showHideFilter = function($scope, $el, $ctrl) {\n var sidebar, target;\n sidebar = $el.find(\"sidebar.filters-bar\");\n sidebar.one(\"transitionend\", function() {\n return timeout(150, function() {\n $rootscope.$broadcast(\"resize\");\n return $('.burndown').css(\"visibility\", \"visible\");\n });\n });\n target = angular.element(\"#show-filters-button\");\n $('.burndown').css(\"visibility\", \"hidden\");\n sidebar.toggleClass(\"active\");\n target.toggleClass(\"active\");\n toggleText(target.find(\".text\"), [\"Remove Filters\", \"Show Filters\"]);\n if (!sidebar.hasClass(\"active\")) {\n $ctrl.resetFilters();\n }\n return $ctrl.toggleActiveFilters();\n };\n linkFilters = function($scope, $el, $attrs, $ctrl) {\n $scope.filtersSearch = {};\n return $el.on(\"click\", \"#show-filters-button\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n return showHideFilter($scope, $el, $ctrl);\n });\n });\n };\n link = function($scope, $el, $attrs, $rootscope) {\n var $ctrl, filters;\n $ctrl = $el.controller();\n linkToolbar($scope, $el, $attrs, $ctrl);\n linkFilters($scope, $el, $attrs, $ctrl);\n linkDoomLine($scope, $el, $attrs, $ctrl);\n $el.find(\".backlog-table-body\").disableSelection();\n filters = $ctrl.getUrlFilters();\n if (filters.statuses || filters.tags || filters.q) {\n showHideFilter($scope, $el, $ctrl);\n }\n $scope.$on(\"showTags\", function() {\n return showHideTags($ctrl);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklog\", [\"$tgRepo\", \"$rootScope\", BacklogDirective]);\n\n UsRolePointsSelectorDirective = function($rootscope, $template) {\n var link, selectionTemplate;\n selectionTemplate = $template.get(\"backlog/us-role-points-popover.html\", true);\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var numberOfRoles, roles;\n roles = _.filter(project.roles, \"computable\");\n numberOfRoles = _.size(roles);\n if (numberOfRoles > 1) {\n return $el.append(selectionTemplate({\n \"roles\": roles\n }));\n } else {\n $el.find(\".icon-arrow-bottom\").remove();\n return $el.find(\".header-points\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"uspoints:select\", function(ctx, roleId, roleName) {\n $el.find(\".popover\").popover().close();\n return $el.find(\".header-points\").html(\"\" + roleName + \"/Total\");\n });\n $scope.$on(\"uspoints:clear-selection\", function(ctx, roleId) {\n $el.find(\".popover\").popover().close();\n return $el.find(\".header-points\").text(\"Points\");\n });\n $el.on(\"click\", function(event) {\n var target;\n target = angular.element(event.target);\n if (target.is(\"span\") || target.is(\"div\")) {\n event.stopPropagation();\n }\n return $el.find(\".popover\").popover().open();\n });\n $el.on(\"click\", \".clear-selection\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $rootscope.$broadcast(\"uspoints:clear-selection\");\n });\n $el.on(\"click\", \".role\", function(event) {\n var rolScope, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n rolScope = target.scope();\n return $rootscope.$broadcast(\"uspoints:select\", target.data(\"role-id\"), target.text());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUsRolePointsSelector\", [\"$rootScope\", \"$tgTemplate\", UsRolePointsSelectorDirective]);\n\n UsPointsDirective = function($repo, $tgTemplate) {\n var link, pointsTemplate, rolesTemplate;\n rolesTemplate = $tgTemplate.get(\"backlog/us-points-roles-popover.html\", true);\n pointsTemplate = $tgTemplate.get(\"backlog/us-points-popover.html\", true);\n link = function($scope, $el, $attrs) {\n var $ctrl, calculateTotalPoints, computableRoles, numberOfRoles, renderPoints, renderPointsSelector, renderRolesSelector, roles, selectedRoleId, updatePointsRoles, updatingSelectedRoleId, us;\n $ctrl = $el.controller();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = null;\n selectedRoleId = null;\n numberOfRoles = _.size(us.points);\n if (numberOfRoles === 1) {\n selectedRoleId = _.keys(us.points)[0];\n }\n roles = [];\n updatePointsRoles = function() {\n return roles = _.map(computableRoles, function(role) {\n var pointId, pointObj;\n pointId = us.points[role.id];\n pointObj = $scope.pointsById[pointId];\n role = _.clone(role, true);\n role.points = pointObj.value != null ? pointObj.value : \"?\";\n return role;\n });\n };\n computableRoles = _.filter($scope.project.roles, \"computable\");\n updatePointsRoles();\n if (roles.length === 0) {\n $el.find(\".icon-arrow-bottom\").remove();\n $el.find(\"a.us-points\").addClass(\"not-clickable\");\n }\n renderPointsSelector = function(us, roleId) {\n var html, points;\n points = _.map($scope.project.points, function(point) {\n point = _.clone(point, true);\n point.selected = us.points[roleId] === point.id ? false : true;\n return point;\n });\n html = pointsTemplate({\n \"points\": points\n });\n $el.find(\".popover\").popover().close();\n $el.find(\".pop-points-open\").remove();\n $el.append(html);\n if ($el.find(\".pop-role:visible\").css(\"left\") == null) {\n $el.find(\".pop-points-open\").css(\"left\", \"110px\");\n }\n return $el.find(\".pop-points-open\").popover().open();\n };\n renderRolesSelector = function(us) {\n var html;\n updatePointsRoles();\n html = rolesTemplate({\n \"roles\": roles\n });\n $el.append(html);\n return $el.find(\".pop-role\").popover().open(function() {\n return $(this).remove();\n });\n };\n renderPoints = function(us, roleId) {\n var dom, pointId, pointObj, totalPoints;\n dom = $el.find(\"a > span.points-value\");\n if (roleId === null || numberOfRoles === 1) {\n totalPoints = us.total_points != null ? us.total_points : \"?\";\n dom.text(totalPoints);\n return dom.parent().prop(\"title\", totalPoints);\n } else {\n pointId = us.points[roleId];\n pointObj = $scope.pointsById[pointId];\n dom.html(\"\" + pointObj.name + \" / \" + us.total_points + \"\");\n return dom.parent().prop(\"title\", \"\" + pointObj.name + \" / \" + us.total_points);\n }\n };\n calculateTotalPoints = function() {\n var values;\n values = _.map(us.points, function(v, k) {\n return $scope.pointsById[v].value;\n });\n values = _.filter(values, function(num) {\n return num != null;\n });\n if (values.length === 0) {\n return \"?\";\n }\n return _.reduce(values, function(acc, num) {\n return acc + num;\n });\n };\n $scope.$watch($attrs.tgBacklogUsPoints, function(us) {\n if (us) {\n return renderPoints(us, selectedRoleId);\n }\n });\n $scope.$on(\"uspoints:select\", function(ctx, roleId, roleName) {\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n renderPoints(us, roleId);\n return selectedRoleId = roleId;\n });\n $scope.$on(\"uspoints:clear-selection\", function(ctx) {\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n renderPoints(us, null);\n return selectedRoleId = null;\n });\n if (roles.length > 0) {\n $el.on(\"click\", \"a.us-points span\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = selectedRoleId;\n if (selectedRoleId != null) {\n return renderPointsSelector(us, selectedRoleId);\n } else {\n return renderRolesSelector(us);\n }\n });\n $el.on(\"click\", \".role\", function(event) {\n var popRolesDom, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n updatingSelectedRoleId = target.data(\"role-id\");\n popRolesDom = $el.find(\".pop-role\");\n popRolesDom.find(\"a\").removeClass(\"active\");\n popRolesDom.find(\"a[data-role-id='\" + updatingSelectedRoleId + \"']\").addClass(\"active\");\n return renderPointsSelector(us, updatingSelectedRoleId);\n });\n $el.on(\"click\", \".point\", function(event) {\n var points, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n $el.find(\".pop-points-open\").hide();\n $el.find(\".pop-role\").hide();\n us = $scope.$eval($attrs.tgBacklogUsPoints);\n points = _.clone(us.points, true);\n points[updatingSelectedRoleId] = target.data(\"point-id\");\n return $scope.$apply(function() {\n us.points = points;\n us.total_points = calculateTotalPoints(us);\n renderPoints(us, selectedRoleId);\n return $repo.save(us).then(function() {\n return $repo.refresh(us).then(function() {\n return $ctrl.loadProjectStats();\n });\n });\n });\n });\n }\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogUsPoints\", [\"$tgRepo\", \"$tgTemplate\", UsPointsDirective]);\n\n tgBacklogGraphDirective = function() {\n var link, redrawChart;\n redrawChart = function(element, dataToDraw) {\n var client_increment_line, colors, data, evolution_line, milestonesRange, optimal_line, options, team_increment_line, width, zero_line, _i, _ref, _results;\n width = element.width();\n element.height(width / 6);\n milestonesRange = (function() {\n _results = [];\n for (var _i = 0, _ref = dataToDraw.milestones.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }\n return _results;\n }).apply(this);\n data = [];\n zero_line = _.map(dataToDraw.milestones, function(ml) {\n return 0;\n });\n data.push({\n data: _.zip(milestonesRange, zero_line),\n lines: {\n fillColor: \"rgba(0,0,0,0)\"\n },\n points: {\n show: false\n }\n });\n optimal_line = _.map(dataToDraw.milestones, function(ml) {\n return ml.optimal;\n });\n data.push({\n data: _.zip(milestonesRange, optimal_line),\n lines: {\n fillColor: \"rgba(120,120,120,0.2)\"\n }\n });\n evolution_line = _.filter(_.map(dataToDraw.milestones, function(ml) {\n return ml.evolution;\n }), function(evolution) {\n return evolution != null;\n });\n data.push({\n data: _.zip(milestonesRange, evolution_line),\n lines: {\n fillColor: \"rgba(102,153,51,0.3)\"\n }\n });\n team_increment_line = _.map(dataToDraw.milestones, function(ml) {\n return -ml[\"team-increment\"];\n });\n data.push({\n data: _.zip(milestonesRange, team_increment_line),\n lines: {\n fillColor: \"rgba(153,51,51,0.3)\"\n }\n });\n client_increment_line = _.map(dataToDraw.milestones, function(ml) {\n return -ml[\"team-increment\"] - ml[\"client-increment\"];\n });\n data.push({\n data: _.zip(milestonesRange, client_increment_line),\n lines: {\n fillColor: \"rgba(255,51,51,0.3)\"\n }\n });\n colors = [\"rgba(0,0,0,1)\", \"rgba(120,120,120,0.2)\", \"rgba(102,153,51,1)\", \"rgba(153,51,51,1)\", \"rgba(255,51,51,1)\"];\n options = {\n grid: {\n borderWidth: {\n top: 0,\n right: 1,\n left: 0,\n bottom: 0\n },\n borderColor: \"#ccc\",\n hoverable: true\n },\n xaxis: {\n ticks: dataToDraw.milestones.length,\n axisLabel: \"Sprints\",\n axisLabelUseCanvas: true,\n axisLabelFontSizePixels: 14,\n axisLabelFontFamily: \"Verdana, Arial, Helvetica, Tahoma, sans-serif\",\n axisLabelPadding: 15,\n tickFormatter: function(val, axis) {\n return \"\";\n }\n },\n series: {\n shadowSize: 0,\n lines: {\n show: true,\n fill: true\n },\n points: {\n show: true,\n fill: true,\n radius: 4,\n lineWidth: 2\n }\n },\n colors: colors,\n tooltip: true,\n tooltipOpts: {\n content: function(label, xval, yval, flotItem) {\n if (flotItem.seriesIndex === 1) {\n return \"Optimal pending points for sprint \" + xval + \" should be \" + yval;\n } else if (flotItem.seriesIndex === 2) {\n return \"Real pending points for sprint \" + xval + \" is \" + yval;\n } else if (flotItem.seriesIndex === 3) {\n return \"Incremented points by team requirements for sprint \" + xval + \" is \" + (Math.abs(yval));\n } else {\n return \"Incremented points by client requirements for sprint \" + xval + \" is \" + (Math.abs(yval));\n }\n }\n }\n };\n element.empty();\n return element.plot(data, options).data(\"plot\");\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch(\"stats\", function(value) {\n if ($scope.stats != null) {\n redrawChart(element, $scope.stats);\n return $scope.$on(\"resize\", function() {\n return redrawChart(element, $scope.stats);\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGmBacklogGraph\", tgBacklogGraphDirective);\n\n TgBacklogProgressBarDirective = function($template) {\n var adjustPercentaje, link, render, template;\n template = $template.get(\"backlog/progress-bar.html\", true);\n render = function(el, projectPointsPercentaje, closedPointsPercentaje) {\n return el.html(template({\n projectPointsPercentaje: projectPointsPercentaje,\n closedPointsPercentaje: closedPointsPercentaje\n }));\n };\n adjustPercentaje = function(percentage) {\n var adjusted;\n adjusted = _.max([0, percentage]);\n adjusted = _.min([100, adjusted]);\n return Math.round(adjusted);\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$watch($attrs.tgBacklogProgressBar, function(stats) {\n var closedPoints, closedPointsPercentaje, definedPoints, projectPointsPercentaje, totalPoints;\n if (stats != null) {\n totalPoints = stats.total_points;\n definedPoints = stats.defined_points;\n closedPoints = stats.closed_points;\n if (definedPoints > totalPoints) {\n projectPointsPercentaje = totalPoints * 100 / definedPoints;\n closedPointsPercentaje = closedPoints * 100 / definedPoints;\n } else {\n projectPointsPercentaje = 100;\n closedPointsPercentaje = closedPoints * 100 / totalPoints;\n }\n projectPointsPercentaje = adjustPercentaje(projectPointsPercentaje - 3);\n closedPointsPercentaje = adjustPercentaje(closedPointsPercentaje - 3);\n return render($el, projectPointsPercentaje, closedPointsPercentaje);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogProgressBar\", [\"$tgTemplate\", TgBacklogProgressBarDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/sortable.coffee\n */\n\n(function() {\n var BacklogEmptySortableDirective, BacklogSortableDirective, SprintSortableDirective, bindOnce, deleteElement, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaBacklog\");\n\n deleteElement = function(el) {\n el.scope().$destroy();\n el.off();\n return el.remove();\n };\n\n BacklogSortableDirective = function($repo, $rs, $rootscope, $tgConfirm) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var filterError;\n if (!(project.my_permissions.indexOf(\"modify_us\") > -1)) {\n return;\n }\n filterError = function() {\n return $tgConfirm.notify(\"error\", \"You can't drop on backlog when filters are open\");\n };\n $el.sortable({\n connectWith: \".sprint\",\n containment: \".wrapper\",\n dropOnEmpty: true,\n placeholder: \"row us-item-row us-item-drag sortable-placeholder\",\n scroll: true,\n tolerance: \"pointer\",\n revert: false,\n cursorAt: {\n right: 15\n },\n stop: function() {\n if ($el.hasClass(\"active-filters\")) {\n $el.sortable(\"cancel\");\n return filterError();\n }\n }\n });\n $el.on(\"multiplesortreceive\", function(event, ui) {\n var itemIndex, itemUs;\n if ($el.hasClass(\"active-filters\")) {\n ui.source.sortable(\"cancel\");\n filterError();\n return;\n }\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n deleteElement(ui.item);\n $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, null);\n return ui.item.find('a').removeClass('noclick');\n });\n $el.on(\"multiplesortstop\", function(event, ui) {\n var index, items, us;\n if ($(ui.items[0]).parent().length === 0) {\n return;\n }\n items = _.sortBy(ui.items, function(item) {\n return $(item).index();\n });\n index = _.min(_.map(items, function(item) {\n return $(item).index();\n }));\n us = _.map(items, function(item) {\n var itemUs;\n item = $(item);\n itemUs = item.scope().us;\n setTimeout(((function(_this) {\n return function() {\n return item.find('a').removeClass('noclick');\n };\n })(this)), 300);\n return itemUs;\n });\n return $scope.$emit(\"sprint:us:move\", us, index, null);\n });\n return $el.on(\"sortstart\", function(event, ui) {\n return ui.item.find('a').addClass('noclick');\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n BacklogEmptySortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n $el.sortable({\n dropOnEmpty: true\n });\n return $el.on(\"sortreceive\", function(event, ui) {\n var itemIndex, itemUs;\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n deleteElement(ui.item);\n $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, null);\n return ui.item.find('a').removeClass('noclick');\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n SprintSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n $el.sortable({\n scroll: true,\n dropOnEmpty: true,\n items: \".sprint-table .milestone-us-item-row\",\n connectWith: \".sprint,.backlog-table-body,.empty-backlog\"\n });\n $el.on(\"multiplesortreceive\", function(event, ui) {\n var index, items, us;\n items = _.sortBy(ui.items, function(item) {\n return $(item).index();\n });\n index = _.min(_.map(items, function(item) {\n return $(item).index();\n }));\n us = _.map(items, function(item) {\n var itemUs;\n item = $(item);\n itemUs = item.scope().us;\n deleteElement(item);\n return itemUs;\n });\n return $scope.$emit(\"sprint:us:move\", us, index, $scope.sprint.id);\n });\n $el.on(\"multiplesortstop\", function(event, ui) {\n var itemIndex, itemUs;\n if (ui.item.parent().length === 0) {\n return;\n }\n itemUs = ui.item.scope().us;\n itemIndex = ui.item.index();\n setTimeout(((function(_this) {\n return function() {\n return ui.item.find('a').removeClass('noclick');\n };\n })(this)), 300);\n return $scope.$emit(\"sprint:us:move\", [itemUs], itemIndex, $scope.sprint.id);\n });\n return $el.on(\"sortstart\", function(event, ui) {\n return ui.item.find('a').addClass('noclick');\n });\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"$tgConfirm\", BacklogSortableDirective]);\n\n module.directive(\"tgBacklogEmptySortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", BacklogEmptySortableDirective]);\n\n module.directive(\"tgSprintSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", SprintSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/backlog/sprints.coffee\n */\n\n(function() {\n var BacklogSprintDirective, BacklogSprintHeaderDirective, ToggleExcludeClosedSprintsVisualization, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaBacklog\");\n\n BacklogSprintDirective = function($repo, $rootscope) {\n var link, refreshSprintTableHeight, slideOptions, sprintTableMinHeight, toggleSprint;\n sprintTableMinHeight = 50;\n slideOptions = {\n duration: 500,\n easing: 'linear'\n };\n refreshSprintTableHeight = (function(_this) {\n return function(sprintTable) {\n if (!sprintTable.find(\".row\").length) {\n return sprintTable.css(\"height\", sprintTableMinHeight);\n } else {\n return sprintTable.css(\"height\", \"auto\");\n }\n };\n })(this);\n toggleSprint = (function(_this) {\n return function($el) {\n var sprintArrow, sprintTable;\n sprintTable = $el.find(\".sprint-table\");\n sprintArrow = $el.find(\".icon-arrow-up\");\n sprintArrow.toggleClass('active');\n sprintTable.toggleClass('open');\n return refreshSprintTableHeight(sprintTable);\n };\n })(this);\n link = function($scope, $el, $attrs) {\n $scope.$watch($attrs.tgBacklogSprint, function(sprint) {\n sprint = $scope.$eval($attrs.tgBacklogSprint);\n if ($scope.$first) {\n return toggleSprint($el);\n } else if (sprint.closed) {\n return $el.addClass(\"sprint-closed\");\n } else if (!$scope.$first && !sprint.closed) {\n toggleSprint($el);\n return $el.addClass(\"sprint-old-open\");\n }\n });\n $el.on(\"click\", \".sprint-name > .icon-arrow-up\", function(event) {\n toggleSprint($el);\n return $el.find(\".sprint-table\").slideToggle(slideOptions);\n });\n $el.on(\"click\", \".sprint-name > .icon-edit\", function(event) {\n var sprint;\n sprint = $scope.$eval($attrs.tgBacklogSprint);\n return $rootscope.$broadcast(\"sprintform:edit\", sprint);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogSprint\", [\"$tgRepo\", \"$rootScope\", BacklogSprintDirective]);\n\n BacklogSprintHeaderDirective = function($navUrls, $template) {\n var link, template;\n template = $template.get(\"backlog/sprint-header.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, isVisible, render;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_milestone\") !== -1;\n };\n isVisible = function() {\n return $scope.project.my_permissions.indexOf(\"view_milestones\") !== -1;\n };\n render = function(sprint) {\n var ctx, estimatedDateRange, finish, start, taskboardUrl;\n taskboardUrl = $navUrls.resolve(\"project-taskboard\", {\n project: $scope.project.slug,\n sprint: sprint.slug\n });\n start = moment(sprint.estimated_start).format(\"DD MMM YYYY\");\n finish = moment(sprint.estimated_finish).format(\"DD MMM YYYY\");\n estimatedDateRange = \"\" + start + \"-\" + finish;\n ctx = {\n name: sprint.name,\n taskboardUrl: taskboardUrl,\n estimatedDateRange: estimatedDateRange,\n closedPoints: sprint.closed_points || 0,\n totalPoints: sprint.total_points || 0,\n isVisible: isVisible(),\n isEditable: isEditable()\n };\n return $el.html(template(ctx));\n };\n $scope.$watch($attrs.ngModel, function(sprint) {\n return render(sprint);\n });\n $scope.$on(\"sprintform:edit:success\", function() {\n return render($model.$modelValue);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgBacklogSprintHeader\", [\"$tgNavUrls\", \"$tgTemplate\", BacklogSprintHeaderDirective]);\n\n ToggleExcludeClosedSprintsVisualization = function($rootscope, $loading) {\n var excludeClosedSprints, link;\n excludeClosedSprints = false;\n link = function($scope, $el, $attrs) {\n $el.on(\"click\", \"\", function(event) {\n $loading.start($el.siblings('.load'));\n return $rootscope.$broadcast(\"backlog:toggle-closed-sprints-visualization\");\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return $scope.$on(\"sprints:loaded\", (function(_this) {\n return function(ctx, sprints) {\n var closedSprints;\n closedSprints = _.filter(sprints, function(sprint) {\n return sprint.closed;\n });\n $loading.finish($el.siblings('.load'));\n if (closedSprints.length > 0) {\n return $el.text(\"Hide closed sprints\");\n } else {\n return $el.text(\"Show closed sprints\");\n }\n };\n })(this));\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBacklogToggleClosedSprintsVisualization\", [\"$rootScope\", \"$tgLoading\", ToggleExcludeClosedSprintsVisualization]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/charts.coffee\n */\n\n(function() {\n var SprintGraphDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaTaskboard\");\n\n SprintGraphDirective = function() {\n var link, redrawChart;\n redrawChart = function(element, dataToDraw) {\n var data, days, options, width;\n width = element.width();\n element.height(240);\n days = _.map(dataToDraw, function(x) {\n return moment(x.day);\n });\n data = [];\n data.unshift({\n data: _.zip(days, _.map(dataToDraw, function(d) {\n return d.optimal_points;\n })),\n lines: {\n fillColor: \"rgba(120,120,120,0.2)\"\n }\n });\n data.unshift({\n data: _.zip(days, _.map(dataToDraw, function(d) {\n return d.open_points;\n })),\n lines: {\n fillColor: \"rgba(102,153,51,0.3)\"\n }\n });\n options = {\n grid: {\n borderWidth: {\n top: 0,\n right: 1,\n left: 0,\n bottom: 0\n },\n borderColor: '#ccc',\n hoverable: true\n },\n xaxis: {\n tickSize: [1, \"day\"],\n min: days[0],\n max: _.last(days),\n mode: \"time\",\n daysNames: days,\n axisLabel: 'Day',\n axisLabelUseCanvas: true,\n axisLabelFontSizePixels: 12,\n axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',\n axisLabelPadding: 5\n },\n yaxis: {\n min: 0\n },\n series: {\n shadowSize: 0,\n lines: {\n show: true,\n fill: true\n },\n points: {\n show: true,\n fill: true,\n radius: 4,\n lineWidth: 2\n }\n },\n colors: [\"rgba(102,153,51,1)\", \"rgba(120,120,120,0.2)\"],\n tooltip: true,\n tooltipOpts: {\n content: function(label, xval, yval, flotItem) {\n var formattedDate, roundedValue;\n formattedDate = moment(xval).format(\"DD MMM\");\n roundedValue = Math.round(yval);\n if (flotItem.seriesIndex === 1) {\n return \"Optimal pending points for day \" + formattedDate + \" should be \" + roundedValue;\n } else {\n return \"Real pending points for day \" + formattedDate + \" is \" + roundedValue;\n }\n }\n }\n };\n element.empty();\n return element.plot(data, options).data(\"plot\");\n };\n link = function($scope, $el, $attrs) {\n var element;\n element = angular.element($el);\n $scope.$on(\"resize\", function() {\n if ($scope.stats) {\n return redrawChart(element, $scope.stats.days);\n }\n });\n $scope.$on(\"taskboard:graph:toggle-visibility\", function() {\n $el.parent().toggleClass('open');\n return timeout(100, function() {\n if ($scope.stats) {\n return redrawChart(element, $scope.stats.days);\n }\n });\n });\n $scope.$watch('stats', function(value) {\n if ($scope.stats == null) {\n return;\n }\n return redrawChart(element, $scope.stats.days);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSprintGraph\", SprintGraphDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/lightboxes.coffee\n */\n\n(function() {\n var CreateBulkTasksDirective, CreateEditTaskDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n CreateEditTaskDirective = function($repo, $model, $rs, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.isNew = true;\n $scope.$on(\"taskform:new\", function(ctx, sprintId, usId) {\n $scope.task = {\n project: $scope.projectId,\n milestone: sprintId,\n user_story: usId,\n is_archived: false,\n status: $scope.project.default_task_status,\n assigned_to: null,\n tags: []\n };\n $scope.isNew = true;\n $el.find(\".button-green span\").html(\"Create\");\n $el.find(\".title\").html(\"New task \");\n $el.find(\".tag-input\").val(\"\");\n return lightboxService.open($el);\n });\n $scope.$on(\"taskform:edit\", function(ctx, task) {\n $scope.task = task;\n $scope.isNew = false;\n $el.find(\".button-green span\").html(\"Save\");\n $el.find(\".title\").html(\"Edit task \");\n $el.find(\".tag-input\").val(\"\");\n return lightboxService.open($el);\n });\n submitButton = $el.find(\".submit-button\");\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var broadcastEvent, form, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n if ($scope.isNew) {\n promise = $repo.create(\"tasks\", $scope.task);\n broadcastEvent = \"taskform:new:success\";\n } else {\n promise = $repo.save($scope.task);\n broadcastEvent = \"taskform:edit:success\";\n }\n $loading.start(submitButton);\n return promise.then(function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n return $rootscope.$broadcast(broadcastEvent, data);\n });\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n CreateBulkTasksDirective = function($repo, $rs, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.form = {\n data: \"\",\n usId: null\n };\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, projectId, promise, sprintId, usId;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n data = $scope.form.data;\n projectId = $scope.projectId;\n sprintId = $scope.form.sprintId;\n usId = $scope.form.usId;\n promise = $rs.tasks.bulkCreate(projectId, sprintId, usId, data);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"taskform:bulk:success\", result);\n return lightboxService.close($el);\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return console.log(\"FAIL\");\n });\n };\n })(this));\n $scope.$on(\"taskform:bulk\", function(ctx, sprintId, usId) {\n lightboxService.open($el);\n return $scope.form = {\n data: \"\",\n sprintId: sprintId,\n usId: usId\n };\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaTaskboard\");\n\n module.directive(\"tgLbCreateEditTask\", [\"$tgRepo\", \"$tgModel\", \"$tgResources\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateEditTaskDirective]);\n\n module.directive(\"tgLbCreateBulkTasks\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateBulkTasksDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard.coffee\n */\n\n(function() {\n var TaskboardController, TaskboardDirective, TaskboardSquishColumnDirective, TaskboardTableHeightFixerDirective, TaskboardTaskDirective, TaskboardUserDirective, bindMethods, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n toggleText = this.taiga.toggleText;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n scopeDefer = this.taiga.scopeDefer;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaTaskboard\");\n\n TaskboardController = (function(_super) {\n __extends(TaskboardController, _super);\n\n TaskboardController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$appTitle\", \"$tgLocation\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function TaskboardController(scope, rootscope, repo, confirm, rs, params, q, appTitle, location, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.appTitle = appTitle;\n this.location = location;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Taskboard\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Taskboard - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TaskboardController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"taskform:bulk:success\", (function(_this) {\n return function() {\n _this.loadTaskboard();\n return _this.analytics.trackEvent(\"task\", \"create\", \"bulk create task on taskboard\", 1);\n };\n })(this));\n this.scope.$on(\"taskform:new:success\", (function(_this) {\n return function() {\n _this.loadTaskboard();\n return _this.analytics.trackEvent(\"task\", \"create\", \"create task on taskboard\", 1);\n };\n })(this));\n this.scope.$on(\"taskform:edit:success\", (function(_this) {\n return function() {\n return _this.loadTaskboard();\n };\n })(this));\n this.scope.$on(\"taskboard:task:move\", this.taskMove);\n return this.scope.$on(\"assigned-to:added\", (function(_this) {\n return function(ctx, userId, task) {\n var promise;\n task.assigned_to = userId;\n promise = _this.repo.save(task);\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n })(this));\n };\n\n TaskboardController.prototype.initializeSubscription = function() {\n var routingKey, routingKey1;\n routingKey = \"changes.project.\" + this.scope.projectId + \".tasks\";\n this.events.subscribe(this.scope, routingKey, (function(_this) {\n return function(message) {\n return _this.loadTaskboard();\n };\n })(this));\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n return this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n _this.refreshTagsColors();\n _this.loadSprintStats();\n return _this.loadSprint();\n };\n })(this));\n };\n\n TaskboardController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(e) {\n return e.id;\n });\n _this.scope.roleById = groupBy(project.roles, function(e) {\n return e.id;\n });\n _this.scope.taskStatusList = _.sortBy(project.task_statuses, \"order\");\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.scope.usStatusById = groupBy(project.us_statuses, function(e) {\n return e.id;\n });\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadSprintStats = function() {\n return this.rs.sprints.stats(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(stats) {\n var completedPointsSum, remainingPointsSum, remainingTasks, totalPointsSum;\n totalPointsSum = _.reduce(_.values(stats.total_points), (function(res, n) {\n return res + n;\n }), 0);\n completedPointsSum = _.reduce(_.values(stats.completed_points), (function(res, n) {\n return res + n;\n }), 0);\n remainingPointsSum = totalPointsSum - completedPointsSum;\n remainingTasks = stats.total_tasks - stats.completed_tasks;\n _this.scope.stats = stats;\n _this.scope.stats.totalPointsSum = totalPointsSum;\n _this.scope.stats.completedPointsSum = completedPointsSum;\n _this.scope.stats.remainingPointsSum = remainingPointsSum;\n _this.scope.stats.remainingTasks = remainingTasks;\n if (stats.totalPointsSum) {\n _this.scope.stats.completedPercentage = Math.round(100 * stats.completedPointsSum / stats.totalPointsSum);\n } else {\n _this.scope.stats.completedPercentage = 0;\n }\n _this.scope.stats.openTasks = stats.total_tasks - stats.completed_tasks;\n return stats;\n };\n })(this));\n };\n\n TaskboardController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadSprint = function() {\n return this.rs.sprints.get(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n _this.scope.userstories = _.sortBy(sprint.user_stories, \"sprint_order\");\n return sprint;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadTasks = function() {\n return this.rs.tasks.list(this.scope.projectId, this.scope.sprintId).then((function(_this) {\n return function(tasks) {\n var status, task, us, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;\n _this.scope.tasks = _.sortBy(tasks, 'taskboard_order');\n _this.scope.usTasks = {};\n _ref = _.union(_this.scope.userstories, [\n {\n id: null\n }\n ]);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n us = _ref[_i];\n _this.scope.usTasks[us.id] = {};\n _ref1 = _this.scope.taskStatusList;\n for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n status = _ref1[_j];\n _this.scope.usTasks[us.id][status.id] = [];\n }\n }\n _ref2 = _this.scope.tasks;\n for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n task = _ref2[_k];\n if ((_this.scope.usTasks[task.user_story] != null) && (_this.scope.usTasks[task.user_story][task.status] != null)) {\n _this.scope.usTasks[task.user_story][task.status].push(task);\n }\n }\n return tasks;\n };\n })(this));\n };\n\n TaskboardController.prototype.loadTaskboard = function() {\n return this.q.all([\n this.refreshTagsColors(), this.loadSprintStats(), this.loadSprint().then((function(_this) {\n return function() {\n return _this.loadTasks();\n };\n })(this))\n ]);\n };\n\n TaskboardController.prototype.loadInitialData = function() {\n var params, promise;\n params = {\n pslug: this.params.pslug,\n sslug: this.params.sslug\n };\n promise = this.repo.resolve(params).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n _this.scope.sprintId = data.milestone;\n _this.initializeSubscription();\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadTaskboard();\n };\n })(this));\n };\n\n TaskboardController.prototype.refreshTasksOrder = function(tasks) {\n var data, items;\n items = this.resortTasks(tasks);\n data = this.prepareBulkUpdateData(items);\n return this.rs.tasks.bulkUpdateTaskTaskboardOrder(this.scope.project.id, data);\n };\n\n TaskboardController.prototype.resortTasks = function(tasks) {\n var index, item, items, _i, _len;\n items = [];\n for (index = _i = 0, _len = tasks.length; _i < _len; index = ++_i) {\n item = tasks[index];\n item[\"taskboard_order\"] = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n TaskboardController.prototype.prepareBulkUpdateData = function(uses) {\n return _.map(uses, function(x) {\n return {\n \"task_id\": x.id,\n \"order\": x[\"taskboard_order\"]\n };\n });\n };\n\n TaskboardController.prototype.taskMove = function(ctx, task, usId, statusId, order) {\n var promise, r, tasks;\n r = this.scope.usTasks[task.user_story][task.status].indexOf(task);\n this.scope.usTasks[task.user_story][task.status].splice(r, 1);\n tasks = this.scope.usTasks[usId][statusId];\n tasks.splice(order, 0, task);\n task.user_story = usId;\n task.status = statusId;\n task.taskboard_order = order;\n promise = this.repo.save(task);\n this.rootscope.$broadcast(\"sprint:task:moved\", task);\n promise.then((function(_this) {\n return function() {\n _this.refreshTasksOrder(tasks);\n return _this.loadSprintStats();\n };\n })(this));\n return promise.then(null, (function(_this) {\n return function() {\n return console.log(\"FAIL TASK SAVE\");\n };\n })(this));\n };\n\n TaskboardController.prototype.addNewTask = function(type, us) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"taskform:new\", this.scope.sprintId, us != null ? us.id : void 0);\n case \"bulk\":\n return this.rootscope.$broadcast(\"taskform:bulk\", this.scope.sprintId, us != null ? us.id : void 0);\n }\n };\n\n TaskboardController.prototype.editTaskAssignedTo = function(task) {\n return this.rootscope.$broadcast(\"assigned-to:add\", task);\n };\n\n return TaskboardController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TaskboardController\", TaskboardController);\n\n TaskboardDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var $ctrl, tableBodyDom;\n $ctrl = $el.controller();\n $el.on(\"click\", \".toggle-analytics-visibility\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.toggleClass('active');\n return $rootscope.$broadcast(\"taskboard:graph:toggle-visibility\");\n });\n tableBodyDom = $el.find(\".taskboard-table-body\");\n tableBodyDom.on(\"scroll\", function(event) {\n var tableHeaderDom, target;\n target = angular.element(event.currentTarget);\n tableHeaderDom = $el.find(\".taskboard-table-header .taskboard-table-inner\");\n return tableHeaderDom.css(\"left\", -1 * target.scrollLeft());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboard\", [\"$rootScope\", TaskboardDirective]);\n\n TaskboardTaskDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $el.disableSelection();\n $scope.$watch(\"task\", function(task) {\n if (task.is_blocked && !$el.hasClass(\"blocked\")) {\n return $el.addClass(\"blocked\");\n } else if (!task.is_blocked && $el.hasClass(\"blocked\")) {\n return $el.removeClass(\"blocked\");\n }\n });\n return $el.find(\".icon-edit\").on(\"click\", function(event) {\n if ($el.find('.icon-edit').hasClass('noclick')) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"taskform:edit\", $scope.task);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardTask\", [\"$rootScope\", TaskboardTaskDirective]);\n\n TaskboardTableHeightFixerDirective = function() {\n var link, mainPadding, renderSize;\n mainPadding = 32;\n renderSize = function($el) {\n var columnHeight, elementOffset, windowHeight;\n elementOffset = $el.offset().top;\n windowHeight = angular.element(window).height();\n columnHeight = windowHeight - elementOffset - mainPadding;\n return $el.css(\"height\", \"\" + columnHeight + \"px\");\n };\n link = function($scope, $el, $attrs) {\n timeout(500, function() {\n return renderSize($el);\n });\n return $scope.$on(\"resize\", function() {\n return renderSize($el);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardTableHeightFixer\", TaskboardTableHeightFixerDirective);\n\n TaskboardSquishColumnDirective = function(rs) {\n var avatarWidth, link;\n avatarWidth = 40;\n link = function($scope, $el, $attrs) {\n var getCeilWidth, recalculateStatusColumnWidth, recalculateTaskboardWidth, refreshTaskboardTableWidth, setStatusColumnWidth;\n $scope.$on(\"sprint:task:moved\", (function(_this) {\n return function() {\n return recalculateTaskboardWidth();\n };\n })(this));\n bindOnce($scope, \"usTasks\", function(project) {\n $scope.statusesFolded = rs.tasks.getStatusColumnModes($scope.project.id);\n $scope.usFolded = rs.tasks.getUsRowModes($scope.project.id, $scope.sprintId);\n return recalculateTaskboardWidth();\n });\n $scope.foldStatus = function(status) {\n $scope.statusesFolded[status.id] = !!!$scope.statusesFolded[status.id];\n rs.tasks.storeStatusColumnModes($scope.projectId, $scope.statusesFolded);\n return recalculateTaskboardWidth();\n };\n $scope.foldUs = function(us) {\n if (!us) {\n $scope.usFolded[null] = !!!$scope.usFolded[null];\n } else {\n $scope.usFolded[us.id] = !!!$scope.usFolded[us.id];\n }\n rs.tasks.storeUsRowModes($scope.projectId, $scope.sprintId, $scope.usFolded);\n return recalculateTaskboardWidth();\n };\n getCeilWidth = (function(_this) {\n return function(usId, statusId) {\n var tasks, tasksMatrixSize, width;\n tasks = $scope.usTasks[usId][statusId].length;\n if ($scope.statusesFolded[statusId]) {\n if (tasks && $scope.usFolded[usId]) {\n tasksMatrixSize = Math.round(Math.sqrt(tasks));\n width = avatarWidth * tasksMatrixSize;\n } else {\n width = avatarWidth;\n }\n return width;\n }\n return 0;\n };\n })(this);\n setStatusColumnWidth = (function(_this) {\n return function(statusId, width) {\n var column;\n column = $el.find(\".squish-status-\" + statusId);\n if (width) {\n return column.css('max-width', width);\n } else {\n return column.css(\"max-width\", 'none');\n }\n };\n })(this);\n refreshTaskboardTableWidth = (function(_this) {\n return function() {\n var columnWidths, columns, totalWidth;\n columnWidths = [];\n columns = $el.find(\".task-colum-name\");\n columnWidths = _.map(columns, function(column) {\n return $(column).outerWidth(true);\n });\n totalWidth = _.reduce(columnWidths, function(total, width) {\n return total + width;\n });\n return $el.find('.taskboard-table-inner').css(\"width\", totalWidth);\n };\n })(this);\n recalculateStatusColumnWidth = (function(_this) {\n return function(statusId) {\n var statusFoldedWidth;\n statusFoldedWidth = getCeilWidth(null, statusId);\n _.forEach($scope.userstories, function(us) {\n var width;\n width = getCeilWidth(us.id, statusId);\n if (width > statusFoldedWidth) {\n return statusFoldedWidth = width;\n }\n });\n return setStatusColumnWidth(statusId, statusFoldedWidth);\n };\n })(this);\n return recalculateTaskboardWidth = (function(_this) {\n return function() {\n _.forEach($scope.taskStatusList, function(status) {\n return recalculateStatusColumnWidth(status.id);\n });\n refreshTaskboardTableWidth();\n };\n })(this);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardSquishColumn\", [\"$tgResources\", TaskboardSquishColumnDirective]);\n\n TaskboardUserDirective = function($log) {\n var clickable, link;\n clickable = false;\n link = function($scope, $el, $attrs) {\n var username_label;\n username_label = $el.parent().find(\"a.task-assigned\");\n username_label.on(\"click\", function(event) {\n var $ctrl;\n if ($el.find('a').hasClass('noclick')) {\n return;\n }\n $ctrl = $el.controller();\n return $ctrl.editTaskAssignedTo($scope.task);\n });\n $scope.$watch('task.assigned_to', function(assigned_to) {\n var user;\n user = $scope.usersById[assigned_to];\n if (user === void 0) {\n _.assign($scope, {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\",\n clickable: clickable\n });\n } else {\n _.assign($scope, {\n name: user.full_name_display,\n imgurl: user.photo,\n clickable: clickable\n });\n }\n return username_label.text($scope.name);\n });\n return bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_task\") > -1) {\n clickable = true;\n return $el.find(\".avatar-assigned-to\").on(\"click\", (function(_this) {\n return function(event) {\n var $ctrl;\n if ($el.find('a').hasClass('noclick')) {\n return;\n }\n $ctrl = $el.controller();\n return $ctrl.editTaskAssignedTo($scope.task);\n };\n })(this));\n }\n });\n };\n return {\n link: link,\n template: \"taskboard/taskboard-user.html\",\n scope: {\n \"usersById\": \"=users\",\n \"project\": \"=\",\n \"task\": \"=\"\n }\n };\n };\n\n module.directive(\"tgTaskboardUserAvatar\", [\"$log\", TaskboardUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/taskboard/sortable.coffee\n */\n\n(function() {\n var TaskboardSortableDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaBacklog\");\n\n TaskboardSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var deleteElement, itemEl, newParentScope, oldParentScope, tdom;\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el;\n deleteElement = function(itemEl) {\n itemEl.scope().$destroy();\n itemEl.off();\n return itemEl.remove();\n };\n tdom.sortable({\n handle: \".taskboard-task-inner\",\n dropOnEmpty: true,\n connectWith: \".taskboard-tasks-box\",\n revert: 400\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemTask, newStatusId, newUsId, oldStatusId, oldUsId, parentEl;\n parentEl = ui.item.parent();\n itemEl = ui.item;\n itemTask = itemEl.scope().task;\n itemIndex = itemEl.index();\n newParentScope = parentEl.scope();\n oldUsId = oldParentScope.us ? oldParentScope.us.id : null;\n oldStatusId = oldParentScope.st.id;\n newUsId = newParentScope.us ? newParentScope.us.id : null;\n newStatusId = newParentScope.st.id;\n if (newStatusId !== oldStatusId || newUsId !== oldUsId) {\n deleteElement(itemEl);\n }\n $scope.$apply(function() {\n return $rootscope.$broadcast(\"taskboard:task:move\", itemTask, newUsId, newStatusId, itemIndex);\n });\n return ui.item.find('a').removeClass('noclick');\n });\n tdom.on(\"sortstart\", function(event, ui) {\n oldParentScope = ui.item.parent().scope();\n return ui.item.find('a').addClass('noclick');\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgTaskboardSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", TaskboardSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban/main.coffee\n */\n\n(function() {\n var KanbanArchivedStatusHeaderDirective, KanbanArchivedStatusIntroDirective, KanbanColumnHeightFixerDirective, KanbanController, KanbanDirective, KanbanSquishColumnDirective, KanbanUserDirective, KanbanUserstoryDirective, KanbanWipLimitDirective, bindMethods, bindOnce, defaultViewMode, defaultViewModes, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaKanban\");\n\n defaultViewMode = \"maximized\";\n\n defaultViewModes = {\n maximized: {\n cardClass: \"kanban-task-maximized\"\n },\n minimized: {\n cardClass: \"kanban-task-minimized\"\n }\n };\n\n KanbanController = (function(_super) {\n __extends(KanbanController, _super);\n\n KanbanController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function KanbanController(scope, rootscope, repo, confirm, rs, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n bindMethods(this);\n this.scope.sectionName = \"Kanban\";\n this.scope.statusViewModes = {};\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Kanban - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n KanbanController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"usform:new:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n _this.refreshTagsColors();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"create userstory on kanban\", 1);\n };\n })(this));\n this.scope.$on(\"usform:bulk:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n return _this.analytics.trackEvent(\"userstory\", \"create\", \"bulk create userstory on kanban\", 1);\n };\n })(this));\n this.scope.$on(\"usform:edit:success\", (function(_this) {\n return function() {\n _this.loadUserstories();\n return _this.refreshTagsColors();\n };\n })(this));\n this.scope.$on(\"assigned-to:added\", this.onAssignedToChanged);\n this.scope.$on(\"kanban:us:move\", this.moveUs);\n this.scope.$on(\"kanban:show-userstories-for-status\", this.loadUserStoriesForStatus);\n return this.scope.$on(\"kanban:hide-userstories-for-status\", this.hideUserStoriesForStatus);\n };\n\n KanbanController.prototype.addNewUs = function(type, statusId) {\n switch (type) {\n case \"standard\":\n return this.rootscope.$broadcast(\"usform:new\", this.scope.projectId, statusId, this.scope.usStatusList);\n case \"bulk\":\n return this.rootscope.$broadcast(\"usform:bulk\", this.scope.projectId, statusId);\n }\n };\n\n KanbanController.prototype.changeUsAssignedTo = function(us) {\n return this.rootscope.$broadcast(\"assigned-to:add\", us);\n };\n\n KanbanController.prototype.onAssignedToChanged = function(ctx, userid, us) {\n var promise;\n us.assigned_to = userid;\n promise = this.repo.save(us);\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n\n KanbanController.prototype.refreshTagsColors = function() {\n return this.rs.projects.tagsColors(this.scope.projectId).then((function(_this) {\n return function(tags_colors) {\n return _this.scope.project.tags_colors = tags_colors;\n };\n })(this));\n };\n\n KanbanController.prototype.loadUserstories = function() {\n var params;\n params = {\n status__is_archived: false\n };\n return this.rs.userstories.listAll(this.scope.projectId, params).then((function(_this) {\n return function(userstories) {\n var status, usByStatus, _i, _len, _ref;\n _this.scope.userstories = userstories;\n usByStatus = _.groupBy(userstories, \"status\");\n _ref = _this.scope.usStatusList;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n status = _ref[_i];\n if (usByStatus[status.id] == null) {\n usByStatus[status.id] = [];\n }\n if (status.is_archived && (_this.scope.usByStatus != null)) {\n usByStatus[status.id] = _this.scope.usByStatus[status.id];\n }\n usByStatus[status.id] = _.sortBy(usByStatus[status.id], \"kanban_order\");\n }\n _this.scope.usByStatus = usByStatus;\n scopeDefer(_this.scope, function() {\n return _this.scope.$broadcast(\"userstories:loaded\", userstories);\n });\n return userstories;\n };\n })(this));\n };\n\n KanbanController.prototype.loadUserStoriesForStatus = function(ctx, statusId) {\n var params;\n params = {\n status: statusId\n };\n return this.rs.userstories.listAll(this.scope.projectId, params).then((function(_this) {\n return function(userstories) {\n _this.scope.usByStatus[statusId] = _.sortBy(userstories, \"kanban_order\");\n _this.scope.$broadcast(\"kanban:shown-userstories-for-status\", statusId, userstories);\n return userstories;\n };\n })(this));\n };\n\n KanbanController.prototype.hideUserStoriesForStatus = function(ctx, statusId) {\n this.scope.usByStatus[statusId] = [];\n return this.scope.$broadcast(\"kanban:hidden-userstories-for-status\", statusId);\n };\n\n KanbanController.prototype.loadKanban = function() {\n return this.q.all([this.refreshTagsColors(), this.loadUserstories()]);\n };\n\n KanbanController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.projectId = project.id;\n _this.scope.points = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(project.points, function(x) {\n return x.id;\n });\n _this.scope.usStatusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.generateStatusViewModes();\n _this.scope.$emit(\"project:loaded\", project);\n return project;\n };\n })(this));\n };\n\n KanbanController.prototype.initializeSubscription = function() {\n var routingKey1;\n routingKey1 = \"changes.project.\" + this.scope.projectId + \".userstories\";\n return this.events.subscribe(this.scope, routingKey1, (function(_this) {\n return function(message) {\n return _this.loadUserstories();\n };\n })(this));\n };\n\n KanbanController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n _this.initializeSubscription();\n return _this.loadKanban().then(function() {\n return _this.scope.$broadcast(\"redraw:wip\");\n });\n };\n })(this));\n };\n\n KanbanController.prototype.generateStatusViewModes = function() {\n var mode, status, storedStatusViewModes, _i, _len, _ref;\n storedStatusViewModes = this.rs.kanban.getStatusViewModes(this.scope.projectId);\n this.scope.statusViewModes = {};\n _ref = this.scope.usStatusList;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n status = _ref[_i];\n mode = storedStatusViewModes[status.id];\n this.scope.statusViewModes[status.id] = _.has(defaultViewModes, mode) ? mode : defaultViewMode;\n }\n return this.storeStatusViewModes();\n };\n\n KanbanController.prototype.storeStatusViewModes = function() {\n return this.rs.kanban.storeStatusViewModes(this.scope.projectId, this.scope.statusViewModes);\n };\n\n KanbanController.prototype.updateStatusViewMode = function(statusId, newViewMode) {\n this.scope.statusViewModes[statusId] = newViewMode;\n return this.storeStatusViewModes();\n };\n\n KanbanController.prototype.getCardClass = function(statusId) {\n var mode;\n mode = this.scope.statusViewModes[statusId] || defaultViewMode;\n return defaultViewModes[mode].cardClass || defaultViewModes[defaultViewMode].cardClass;\n };\n\n KanbanController.prototype.prepareBulkUpdateData = function(uses, field) {\n if (field == null) {\n field = \"kanban_order\";\n }\n return _.map(uses, function(x) {\n return {\n \"us_id\": x.id,\n \"order\": x[field]\n };\n });\n };\n\n KanbanController.prototype.resortUserStories = function(uses) {\n var index, item, items, _i, _len;\n items = [];\n for (index = _i = 0, _len = uses.length; _i < _len; index = ++_i) {\n item = uses[index];\n item.kanban_order = index;\n if (item.isModified()) {\n items.push(item);\n }\n }\n return items;\n };\n\n KanbanController.prototype.moveUs = function(ctx, us, oldStatusId, newStatusId, index) {\n var itemsToSave, promise, r;\n if (oldStatusId !== newStatusId) {\n r = this.scope.usByStatus[oldStatusId].indexOf(us);\n this.scope.usByStatus[oldStatusId].splice(r, 1);\n this.scope.usByStatus[newStatusId].splice(index, 0, us);\n us.status = newStatusId;\n } else {\n r = this.scope.usByStatus[newStatusId].indexOf(us);\n this.scope.usByStatus[newStatusId].splice(r, 1);\n this.scope.usByStatus[newStatusId].splice(index, 0, us);\n }\n itemsToSave = this.resortUserStories(this.scope.usByStatus[newStatusId]);\n this.scope.usByStatus[newStatusId] = _.sortBy(this.scope.usByStatus[newStatusId], \"kanban_order\");\n promise = this.repo.save(us);\n promise = promise.then((function(_this) {\n return function() {\n var data;\n itemsToSave = _.reject(itemsToSave, {\n \"id\": us.id\n });\n data = _this.prepareBulkUpdateData(itemsToSave);\n return _this.rs.userstories.bulkUpdateKanbanOrder(us.project, data).then(function() {\n return itemsToSave;\n });\n };\n })(this));\n return promise;\n };\n\n return KanbanController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"KanbanController\", KanbanController);\n\n KanbanDirective = function($repo, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n var tableBodyDom;\n tableBodyDom = $el.find(\".kanban-table-body\");\n tableBodyDom.on(\"scroll\", function(event) {\n var tableHeaderDom, target;\n target = angular.element(event.currentTarget);\n tableHeaderDom = $el.find(\".kanban-table-header .kanban-table-inner\");\n return tableHeaderDom.css(\"left\", -1 * target.scrollLeft());\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanban\", [\"$tgRepo\", \"$rootScope\", KanbanDirective]);\n\n KanbanColumnHeightFixerDirective = function() {\n var link, mainPadding, renderSize, scrollPadding;\n mainPadding = 32;\n scrollPadding = 0;\n renderSize = function($el) {\n var columnHeight, elementOffset, windowHeight;\n elementOffset = $el.parent().parent().offset().top;\n windowHeight = angular.element(window).height();\n columnHeight = windowHeight - elementOffset - mainPadding - scrollPadding;\n return $el.css(\"height\", \"\" + columnHeight + \"px\");\n };\n link = function($scope, $el, $attrs) {\n timeout(500, function() {\n return renderSize($el);\n });\n $scope.$on(\"resize\", function() {\n return renderSize($el);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanColumnHeightFixer\", KanbanColumnHeightFixerDirective);\n\n KanbanArchivedStatusHeaderDirective = function($rootscope) {\n var hideArchivedText, link, showArchivedText;\n showArchivedText = \"Show archived\";\n hideArchivedText = \"Hide archived\";\n link = function($scope, $el, $attrs) {\n var hidden, status;\n status = $scope.$eval($attrs.tgKanbanArchivedStatusHeader);\n hidden = true;\n $scope[\"class\"] = \"icon icon-open-eye\";\n $scope.title = showArchivedText;\n $el.on(\"click\", function(event) {\n hidden = !hidden;\n return $scope.$apply(function() {\n if (hidden) {\n $scope[\"class\"] = \"icon icon-open-eye\";\n $scope.title = showArchivedText;\n return $rootscope.$broadcast(\"kanban:hide-userstories-for-status\", status.id);\n } else {\n $scope[\"class\"] = \"icon icon-closed-eye\";\n $scope.title = hideArchivedText;\n return $rootscope.$broadcast(\"kanban:show-userstories-for-status\", status.id);\n }\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanArchivedStatusHeader\", [\"$rootScope\", KanbanArchivedStatusHeaderDirective]);\n\n KanbanArchivedStatusIntroDirective = function() {\n var hiddenUserStoriexText, link, userStories;\n hiddenUserStoriexText = \"The user stories in this status are hidden by default\";\n userStories = [];\n link = function($scope, $el, $attrs) {\n var status, updateIntroText;\n status = $scope.$eval($attrs.tgKanbanArchivedStatusIntro);\n $el.text(hiddenUserStoriexText);\n updateIntroText = function() {\n if (userStories.length > 0) {\n return $el.text(\"\");\n } else {\n return $el.text(hiddenUserStoriexText);\n }\n };\n $scope.$on(\"kanban:us:move\", function(ctx, itemUs, oldStatusId, newStatusId, itemIndex) {\n var r;\n if (status.id === newStatusId) {\n if (status.id === oldStatusId) {\n r = userStories.indexOf(itemUs);\n userStories.splice(r, 1);\n userStories.splice(itemIndex, 0, itemUs);\n } else {\n itemUs.isArchived = true;\n userStories.splice(itemIndex, 0, itemUs);\n }\n } else if (status.id === oldStatusId) {\n itemUs.isArchived = false;\n r = userStories.indexOf(itemUs);\n userStories.splice(r, 1);\n }\n return updateIntroText();\n });\n $scope.$on(\"kanban:shown-userstories-for-status\", function(ctx, statusId, userStoriesLoaded) {\n if (statusId === status.id) {\n userStories = _.filter(userStoriesLoaded, function(us) {\n return us.status === status.id;\n });\n return updateIntroText();\n }\n });\n $scope.$on(\"kanban:hidden-userstories-for-status\", function(ctx, statusId) {\n if (statusId === status.id) {\n userStories = [];\n return updateIntroText();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanArchivedStatusIntro\", KanbanArchivedStatusIntroDirective);\n\n KanbanUserstoryDirective = function($rootscope) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n $el.disableSelection();\n $scope.$watch(\"us\", function(us) {\n if (us.is_blocked && !$el.hasClass(\"blocked\")) {\n return $el.addClass(\"blocked\");\n } else if (!us.is_blocked && $el.hasClass(\"blocked\")) {\n return $el.removeClass(\"blocked\");\n }\n });\n $el.find(\".icon-edit\").on(\"click\", function(event) {\n if ($el.find(\".icon-edit\").hasClass(\"noclick\")) {\n return;\n }\n return $scope.$apply(function() {\n return $rootscope.$broadcast(\"usform:edit\", $model.$modelValue);\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n templateUrl: \"kanban/kanban-task.html\",\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgKanbanUserstory\", [\"$rootScope\", KanbanUserstoryDirective]);\n\n KanbanSquishColumnDirective = function(rs) {\n var link;\n link = function($scope, $el, $attrs) {\n var updateTableWidth;\n $scope.$on(\"project:loaded\", function(event, project) {\n $scope.folds = rs.kanban.getStatusColumnModes(project.id);\n return updateTableWidth();\n });\n $scope.foldStatus = function(status) {\n $scope.folds[status.id] = !!!$scope.folds[status.id];\n rs.kanban.storeStatusColumnModes($scope.projectId, $scope.folds);\n updateTableWidth();\n };\n return updateTableWidth = function() {\n var columnWidths, totalWidth;\n columnWidths = _.map($scope.usStatusList, function(status) {\n if ($scope.folds[status.id]) {\n return 40;\n } else {\n return 310;\n }\n });\n totalWidth = _.reduce(columnWidths, function(total, width) {\n return total + width;\n });\n return $el.find('.kanban-table-inner').css(\"width\", totalWidth);\n };\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanSquishColumn\", [\"$tgResources\", KanbanSquishColumnDirective]);\n\n KanbanWipLimitDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var redrawWipLimit;\n $el.disableSelection();\n redrawWipLimit = function() {\n $el.find(\".kanban-wip-limit\").remove();\n return timeout(200, function() {\n var element;\n element = $el.find(\".kanban-task\")[$scope.$eval($attrs.tgKanbanWipLimit)];\n if (element) {\n return angular.element(element).before(\"
    \");\n }\n });\n };\n $scope.$on(\"redraw:wip\", redrawWipLimit);\n $scope.$on(\"kanban:us:move\", redrawWipLimit);\n $scope.$on(\"usform:new:success\", redrawWipLimit);\n $scope.$on(\"usform:bulk:success\", redrawWipLimit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanWipLimit\", KanbanWipLimitDirective);\n\n KanbanUserDirective = function($log) {\n var clickable, link, template;\n template = _.template(\"
    \\n class=\\\"not-clickable\\\"<% } %>>\\n \\\" alt=\\\"<%- name %>\\\" class=\\\"avatar\\\">\\n \\n
    \");\n clickable = false;\n link = function($scope, $el, $attrs, $model) {\n var render, wtid;\n if (!$attrs.tgKanbanUserAvatar) {\n return $log.error(\"KanbanUserDirective: no attr is defined\");\n }\n wtid = $scope.$watch($attrs.tgKanbanUserAvatar, function(v) {\n var user;\n if ($scope.usersById == null) {\n $log.error(\"KanbanUserDirective requires userById set in scope.\");\n return wtid();\n } else {\n user = $scope.usersById[v];\n return render(user);\n }\n });\n render = function(user) {\n var ctx, html, username_label;\n if (user === void 0) {\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\",\n clickable: clickable\n };\n } else {\n ctx = {\n name: user.full_name_display,\n imgurl: user.photo,\n clickable: clickable\n };\n }\n html = template(ctx);\n $el.html(html);\n username_label = $el.parent().find(\"a.task-assigned\");\n username_label.html(ctx.name);\n return username_label.on(\"click\", function(event) {\n var $ctrl, us;\n if ($el.find(\"a\").hasClass(\"noclick\")) {\n return;\n }\n us = $model.$modelValue;\n $ctrl = $el.controller();\n return $ctrl.changeUsAssignedTo(us);\n });\n };\n bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_us\") > -1) {\n clickable = true;\n return $el.on(\"click\", (function(_this) {\n return function(event) {\n var $ctrl, us;\n if ($el.find(\"a\").hasClass(\"noclick\")) {\n return;\n }\n us = $model.$modelValue;\n $ctrl = $el.controller();\n return $ctrl.changeUsAssignedTo(us);\n };\n })(this));\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgKanbanUserAvatar\", [\"$log\", KanbanUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/kanban/sortable.coffee\n */\n\n(function() {\n var KanbanSortableDirective, bindOnce, groupBy, mixOf, module, scopeDefer, taiga, timeout, toggleText;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toggleText = this.taiga.toggleText;\n\n scopeDefer = this.taiga.scopeDefer;\n\n bindOnce = this.taiga.bindOnce;\n\n groupBy = this.taiga.groupBy;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaKanban\");\n\n KanbanSortableDirective = function($repo, $rs, $rootscope) {\n var link;\n link = function($scope, $el, $attrs) {\n bindOnce($scope, \"project\", function(project) {\n var deleteElement, itemEl, newParentScope, oldParentScope, tdom;\n if (!(project.my_permissions.indexOf(\"modify_us\") > -1)) {\n return;\n }\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el;\n deleteElement = function(itemEl) {\n itemEl.scope().$destroy();\n itemEl.off();\n return itemEl.remove();\n };\n tdom.sortable({\n handle: \".kanban-task-inner\",\n dropOnEmpty: true,\n connectWith: \".kanban-uses-box\",\n revert: 400\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemUs, newStatusId, oldStatusId, parentEl;\n parentEl = ui.item.parent();\n itemEl = ui.item;\n itemUs = itemEl.scope().us;\n itemIndex = itemEl.index();\n newParentScope = parentEl.scope();\n newStatusId = newParentScope.s.id;\n oldStatusId = oldParentScope.s.id;\n if (newStatusId !== oldStatusId) {\n deleteElement(itemEl);\n }\n $scope.$apply(function() {\n return $rootscope.$broadcast(\"kanban:us:move\", itemUs, itemUs.status, newStatusId, itemIndex);\n });\n return ui.item.find('a').removeClass('noclick');\n });\n return tdom.on(\"sortstart\", function(event, ui) {\n oldParentScope = ui.item.parent().scope();\n return ui.item.find('a').addClass('noclick');\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgKanbanSortable\", [\"$tgRepo\", \"$tgResources\", \"$rootScope\", KanbanSortableDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/detail.coffee\n */\n\n(function() {\n var IssueDetailController, IssuePriorityButtonDirective, IssueSeverityButtonDirective, IssueStatusButtonDirective, IssueStatusDisplayDirective, IssueTypeButtonDirective, PromoteIssueToUsButtonDirective, bindOnce, groupBy, joinStr, mixOf, module, taiga, toString,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaIssues\");\n\n IssueDetailController = (function(_super) {\n __extends(IssueDetailController, _super);\n\n IssueDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgAnalytics\", \"$tgNavUrls\", \"tgLoader\"];\n\n function IssueDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, analytics, navUrls, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.analytics = analytics;\n this.navUrls = navUrls;\n this.scope.issueRef = this.params.issueref;\n this.scope.sectionName = \"Issue Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.issue.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n IssueDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.rootscope.$broadcast(\"history:reload\");\n return _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on issue\", 1);\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"promote-issue-to-us:success\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"issue\", \"promoteToUserstory\", \"promote issue to userstory\", 1);\n _this.rootscope.$broadcast(\"history:reload\");\n return _this.loadIssue();\n };\n })(this));\n };\n\n IssueDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n if (this.scope.project.is_issues_activated) {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-issues\", ctx);\n } else {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n }\n };\n\n IssueDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.issue_statuses;\n _this.scope.statusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.typeById = groupBy(project.issue_types, function(x) {\n return x.id;\n });\n _this.scope.typeList = _.sortBy(project.issue_types, \"order\");\n _this.scope.severityList = project.severities;\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.priorityList = project.priorities;\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n IssueDetailController.prototype.loadIssue = function() {\n return this.rs.issues.getByRef(this.scope.projectId, this.params.issueref).then((function(_this) {\n return function(issue) {\n var ctx;\n _this.scope.issue = issue;\n _this.scope.issueId = issue.id;\n _this.scope.commentModel = issue;\n if (_this.scope.issue.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.issue.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-issues-detail\", ctx);\n }\n if (_this.scope.issue.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.issue.neighbors.next.ref\n };\n return _this.scope.nextUrl = _this.navUrls.resolve(\"project-issues-detail\", ctx);\n }\n };\n })(this));\n };\n\n IssueDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadIssue();\n };\n })(this));\n };\n\n return IssueDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"IssueDetailController\", IssueDetailController);\n\n IssueStatusDisplayDirective = function($template) {\n var link, template;\n template = $template.get(\"common/components/status-display.html\", true);\n link = function($scope, $el, $attrs) {\n var render;\n render = function(issue) {\n var html;\n html = template({\n status: $scope.statusById[issue.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue != null) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueStatusDisplay\", [\"$tgTemplate\", IssueStatusDisplayDirective]);\n\n IssueStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"issue/issues-status-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, status;\n status = $scope.statusById[issue.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(value, issue) {\n var onError, onSuccess;\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save(value).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var issue, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.status = target.data(\"status-id\");\n $model.$setViewValue(issue);\n return save($model.$modelValue, issue);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", IssueStatusButtonDirective]);\n\n IssueTypeButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"issue/issue-type-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, type;\n type = $scope.typeById[issue.type];\n html = template({\n type: type,\n typees: $scope.typeList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(type) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.type = type;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".type-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-type\").popover().open();\n });\n $el.on(\"click\", \".type\", function(event) {\n var target, type;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n type = target.data(\"type-id\");\n return save(type);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueTypeButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", IssueTypeButtonDirective]);\n\n IssueSeverityButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"issue/issue-severity-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, severity;\n severity = $scope.severityById[issue.severity];\n html = template({\n severity: severity,\n severityes: $scope.severityList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(severity) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.severity = severity;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".severity-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-severity\").popover().open();\n });\n $el.on(\"click\", \".severity\", function(event) {\n var severity, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n severity = target.data(\"severity-id\");\n return save(severity);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssueSeverityButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", IssueSeverityButtonDirective]);\n\n IssuePriorityButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"issue/issue-priority-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_issue\") !== -1;\n };\n render = (function(_this) {\n return function(issue) {\n var html, priority;\n priority = $scope.priorityById[issue.priority];\n html = template({\n priority: priority,\n priorityes: $scope.priorityList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(priority) {\n var issue, onError, onSuccess;\n $.fn.popover().closeAll();\n issue = $model.$modelValue.clone();\n issue.priority = priority;\n $model.$setViewValue(issue);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n issue.revert();\n $model.$setViewValue(issue);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".priority-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-priority\").popover().open();\n });\n $el.on(\"click\", \".priority\", function(event) {\n var priority, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n priority = target.data(\"priority-id\");\n return save(priority);\n });\n $scope.$watch($attrs.ngModel, function(issue) {\n if (issue) {\n return render(issue);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgIssuePriorityButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", IssuePriorityButtonDirective]);\n\n PromoteIssueToUsButtonDirective = function($rootScope, $repo, $confirm, $qqueue) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var save;\n save = $qqueue.bindAdd((function(_this) {\n return function(issue, finish) {\n var data, onError, onSuccess;\n data = {\n generated_from_issue: issue.id,\n project: issue.project,\n subject: issue.subject,\n description: issue.description,\n tags: issue.tags,\n is_blocked: issue.is_blocked,\n blocked_note: issue.blocked_note\n };\n onSuccess = function() {\n finish();\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"promote-issue-to-us:success\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\");\n };\n return $repo.create(\"userstories\", data).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \"a\", function(event) {\n var issue, message, subtitle, title;\n event.preventDefault();\n issue = $model.$modelValue;\n title = \"Promote this issue to a new user story\";\n message = \"Are you sure you want to create a new US from this Issue?\";\n subtitle = issue.subject;\n return $confirm.ask(title, subtitle, message).then((function(_this) {\n return function(finish) {\n return save(issue, finish);\n };\n })(this));\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n restrict: \"AE\",\n require: \"ngModel\",\n templateUrl: \"issue/promote-issue-to-us-button.html\",\n link: link\n };\n };\n\n module.directive(\"tgPromoteIssueToUsButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgQqueue\", PromoteIssueToUsButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/lightboxes.coffee\n */\n\n(function() {\n var CreateBulkIssuesDirective, CreateIssueDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaIssues\");\n\n CreateIssueDirective = function($repo, $confirm, $rootscope, lightboxService, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley();\n $scope.issue = {};\n $scope.$on(\"issueform:new\", function(ctx, project) {\n $el.find(\".tag-input\").val(\"\");\n lightboxService.open($el);\n return $scope.issue = {\n project: project.id,\n subject: \"\",\n status: project.default_issue_status,\n type: project.default_issue_type,\n priority: project.default_priority,\n severity: project.default_severity,\n tags: []\n };\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"issues\", $scope.issue);\n promise.then(function(data) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"issueform:new:success\", data);\n lightboxService.close($el);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateIssue\", [\"$tgRepo\", \"$tgConfirm\", \"$rootScope\", \"lightboxService\", \"$tgLoading\", CreateIssueDirective]);\n\n CreateBulkIssuesDirective = function($repo, $rs, $confirm, $rootscope, $loading, lightboxService) {\n var link;\n link = function($scope, $el, attrs) {\n var submit, submitButton;\n $scope.$on(\"issueform:bulk\", function(ctx, projectId, status) {\n lightboxService.open($el);\n return $scope[\"new\"] = {\n projectId: projectId,\n bulk: \"\"\n };\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var data, form, projectId, promise;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n data = $scope[\"new\"].bulk;\n projectId = $scope[\"new\"].projectId;\n promise = $rs.issues.bulkCreate(projectId, data);\n promise.then(function(result) {\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"issueform:new:success\", result);\n lightboxService.close($el);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateBulkIssues\", [\"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$rootScope\", \"$tgLoading\", \"lightboxService\", CreateBulkIssuesDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/list.coffee\n */\n\n(function() {\n var IssueAssignedToInlineEditionDirective, IssueStatusInlineEditionDirective, IssuesController, IssuesDirective, IssuesFiltersDirective, bindOnce, debounceLeading, groupBy, joinStr, mixOf, module, startswith, taiga, toString, trim,\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounceLeading = this.taiga.debounceLeading;\n\n startswith = this.taiga.startswith;\n\n module = angular.module(\"taigaIssues\");\n\n IssuesController = (function(_super) {\n __extends(IssuesController, _super);\n\n IssuesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$tgUrls\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$appTitle\", \"$tgNavUrls\", \"$tgEvents\", \"$tgAnalytics\", \"tgLoader\"];\n\n function IssuesController(scope, rootscope, repo, confirm, rs, urls, params, q, location, appTitle, navUrls, events, analytics, tgLoader) {\n var filters, promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.urls = urls;\n this.params = params;\n this.q = q;\n this.location = location;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.events = events;\n this.analytics = analytics;\n this.loadIssues = __bind(this.loadIssues, this);\n this.scope.sectionName = \"Issues\";\n this.scope.filters = {};\n if (_.isEmpty(this.location.search())) {\n filters = this.rs.issues.getFilters(this.params.pslug);\n filters.page = 1;\n this.location.search(filters);\n this.location.replace();\n return;\n }\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Issues - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n this.scope.$on(\"issueform:new:success\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"issue\", \"create\", \"create issue on issues list\", 1);\n _this.loadIssues();\n return _this.loadFilters();\n };\n })(this));\n }\n\n IssuesController.prototype.initializeSubscription = function() {\n var routingKey;\n routingKey = \"changes.project.\" + this.scope.projectId + \".issues\";\n return this.events.subscribe(this.scope, routingKey, (function(_this) {\n return function(message) {\n return _this.loadIssues();\n };\n })(this));\n };\n\n IssuesController.prototype.storeFilters = function() {\n return this.rs.issues.storeFilters(this.params.pslug, this.location.search());\n };\n\n IssuesController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issueStatusById = groupBy(project.issue_statuses, function(x) {\n return x.id;\n });\n _this.scope.issueStatusList = _.sortBy(project.issue_statuses, \"order\");\n _this.scope.severityById = groupBy(project.severities, function(x) {\n return x.id;\n });\n _this.scope.severityList = _.sortBy(project.severities, \"order\");\n _this.scope.priorityById = groupBy(project.priorities, function(x) {\n return x.id;\n });\n _this.scope.priorityList = _.sortBy(project.priorities, \"order\");\n _this.scope.issueTypes = _.sortBy(project.issue_types, \"order\");\n _this.scope.issueTypeById = groupBy(project.issue_types, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n IssuesController.prototype.getUrlFilters = function() {\n var filters;\n filters = _.pick(this.location.search(), \"page\", \"tags\", \"statuses\", \"types\", \"q\", \"severities\", \"priorities\", \"assignedTo\", \"createdBy\", \"orderBy\");\n if (!filters.page) {\n filters.page = 1;\n }\n return filters;\n };\n\n IssuesController.prototype.getUrlFilter = function(name) {\n var filters;\n filters = _.pick(this.location.search(), name);\n return filters[name];\n };\n\n IssuesController.prototype.loadMyFilters = function() {\n return this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n return _.map(filters, function(value, key) {\n return {\n id: key,\n name: key,\n type: \"myFilters\",\n selected: false\n };\n });\n };\n })(this));\n };\n\n IssuesController.prototype.removeNotExistingFiltersFromUrl = function() {\n var currentSearch, existingValues, filterName, filterValue, splittedValues, urlfilters;\n currentSearch = this.location.search();\n urlfilters = this.getUrlFilters();\n for (filterName in urlfilters) {\n filterValue = urlfilters[filterName];\n if (filterName === \"page\" || filterName === \"orderBy\" || filterName === \"q\") {\n continue;\n }\n if (filterName === \"tags\") {\n splittedValues = _.map((\"\" + filterValue).split(\",\"));\n } else {\n splittedValues = _.map((\"\" + filterValue).split(\",\"), function(x) {\n if (x === \"null\") {\n return null;\n } else {\n return parseInt(x);\n }\n });\n }\n existingValues = _.intersection(splittedValues, _.map(this.scope.filters[filterName], \"id\"));\n if (splittedValues.length !== existingValues.length) {\n this.location.search(filterName, existingValues.join());\n }\n }\n if (currentSearch !== this.location.search()) {\n return this.location.replace();\n }\n };\n\n IssuesController.prototype.markSelectedFilters = function(filters, urlfilters) {\n var isSelected, key, name, obj, searchdata, val, value, _i, _len, _ref, _ref1, _results;\n searchdata = {};\n _ref = _.omit(urlfilters, \"page\", \"orderBy\");\n for (name in _ref) {\n value = _ref[name];\n if (searchdata[name] == null) {\n searchdata[name] = {};\n }\n _ref1 = (\"\" + value).split(\",\");\n for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n val = _ref1[_i];\n searchdata[name][val] = true;\n }\n }\n isSelected = function(type, id) {\n if ((searchdata[type] != null) && searchdata[type][id]) {\n return true;\n }\n return false;\n };\n _results = [];\n for (key in filters) {\n value = filters[key];\n _results.push((function() {\n var _j, _len1, _results1;\n _results1 = [];\n for (_j = 0, _len1 = value.length; _j < _len1; _j++) {\n obj = value[_j];\n _results1.push(obj.selected = isSelected(obj.type, obj.id) ? true : void 0);\n }\n return _results1;\n })());\n }\n return _results;\n };\n\n IssuesController.prototype.loadFilters = function() {\n var promise, urlfilters;\n urlfilters = this.getUrlFilters();\n if (urlfilters.q) {\n this.scope.filtersQ = urlfilters.q;\n }\n promise = this.loadMyFilters().then((function(_this) {\n return function(myFilters) {\n _this.scope.filters.myFilters = myFilters;\n return myFilters;\n };\n })(this));\n promise = promise.then((function(_this) {\n return function() {\n return _this.rs.issues.filtersData(_this.scope.projectId);\n };\n })(this));\n return promise.then((function(_this) {\n return function(data) {\n var choicesFiltersFormat, tagsFilterFormat, usersFiltersFormat;\n usersFiltersFormat = function(users, type, unknownOption) {\n var reformatedUsers, unknownItem;\n reformatedUsers = _.map(users, function(t) {\n return {\n id: t[0],\n count: t[1],\n type: type,\n name: t[0] ? _this.scope.usersById[t[0]].full_name_display : unknownOption\n };\n });\n unknownItem = _.remove(reformatedUsers, function(u) {\n return !u.id;\n });\n reformatedUsers = _.sortBy(reformatedUsers, function(u) {\n return u.name.toUpperCase();\n });\n if (unknownItem.length > 0) {\n reformatedUsers.unshift(unknownItem[0]);\n }\n return reformatedUsers;\n };\n choicesFiltersFormat = function(choices, type, byIdObject) {\n return _.map(choices, function(t) {\n return {\n id: t[0],\n name: byIdObject[t[0]].name,\n color: byIdObject[t[0]].color,\n count: t[1],\n type: type\n };\n });\n };\n tagsFilterFormat = function(tags) {\n return _.map(tags, function(t) {\n return {\n id: t[0],\n name: t[0],\n color: _this.scope.project.tags_colors[t[0]],\n count: t[1],\n type: \"tags\"\n };\n });\n };\n _this.scope.filters.statuses = choicesFiltersFormat(data.statuses, \"statuses\", _this.scope.issueStatusById);\n _this.scope.filters.severities = choicesFiltersFormat(data.severities, \"severities\", _this.scope.severityById);\n _this.scope.filters.priorities = choicesFiltersFormat(data.priorities, \"priorities\", _this.scope.priorityById);\n _this.scope.filters.assignedTo = usersFiltersFormat(data.assigned_to, \"assignedTo\", \"Unassigned\");\n _this.scope.filters.createdBy = usersFiltersFormat(data.created_by, \"createdBy\", \"Unknown\");\n _this.scope.filters.types = choicesFiltersFormat(data.types, \"types\", _this.scope.issueTypeById);\n _this.scope.filters.tags = tagsFilterFormat(data.tags);\n _this.removeNotExistingFiltersFromUrl();\n _this.markSelectedFilters(_this.scope.filters, urlfilters);\n return _this.rootscope.$broadcast(\"filters:loaded\", _this.scope.filters);\n };\n })(this));\n };\n\n IssuesController.prototype.loadIssuesRequests = 0;\n\n IssuesController.prototype.loadIssues = function() {\n var name, promise, values, _ref;\n this.scope.urlFilters = this.getUrlFilters();\n this.scope.httpParams = {};\n _ref = this.scope.urlFilters;\n for (name in _ref) {\n values = _ref[name];\n if (name === \"severities\") {\n name = \"severity\";\n } else if (name === \"orderBy\") {\n name = \"order_by\";\n } else if (name === \"priorities\") {\n name = \"priority\";\n } else if (name === \"assignedTo\") {\n name = \"assigned_to\";\n } else if (name === \"createdBy\") {\n name = \"owner\";\n } else if (name === \"statuses\") {\n name = \"status\";\n } else if (name === \"types\") {\n name = \"type\";\n }\n this.scope.httpParams[name] = values;\n }\n promise = this.rs.issues.list(this.scope.projectId, this.scope.httpParams);\n this.loadIssuesRequests += 1;\n promise.index = this.loadIssuesRequests;\n return promise.then((function(_this) {\n return function(data) {\n if (promise.index === _this.loadIssuesRequests) {\n _this.scope.issues = data.models;\n _this.scope.page = data.current;\n _this.scope.count = data.count;\n _this.scope.paginatedBy = data.paginatedBy;\n }\n return data;\n };\n })(this));\n };\n\n IssuesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n _this.initializeSubscription();\n return _this.q.all([_this.loadFilters(), _this.loadIssues()]);\n };\n })(this));\n };\n\n IssuesController.prototype.saveCurrentFiltersTo = function(newFilter) {\n var deferred;\n deferred = this.q.defer();\n this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n filters[newFilter] = _this.location.search();\n return _this.rs.issues.storeMyFilters(_this.scope.projectId, filters).then(function() {\n return deferred.resolve();\n });\n };\n })(this));\n return deferred.promise;\n };\n\n IssuesController.prototype.deleteMyFilter = function(filter) {\n var deferred;\n deferred = this.q.defer();\n this.rs.issues.getMyFilters(this.scope.projectId).then((function(_this) {\n return function(filters) {\n delete filters[filter];\n return _this.rs.issues.storeMyFilters(_this.scope.projectId, filters).then(function() {\n return deferred.resolve();\n });\n };\n })(this));\n return deferred.promise;\n };\n\n IssuesController.prototype.addNewIssue = function() {\n return this.rootscope.$broadcast(\"issueform:new\", this.scope.project);\n };\n\n IssuesController.prototype.addIssuesInBulk = function() {\n return this.rootscope.$broadcast(\"issueform:bulk\", this.scope.projectId);\n };\n\n return IssuesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"IssuesController\", IssuesController);\n\n IssuesDirective = function($log, $location, $template) {\n var link, linkOrdering, linkPagination, template;\n template = $template.get(\"issue/issue-paginator.html\", true);\n linkPagination = function($scope, $el, $attrs, $ctrl) {\n var $pagEl, afterCurrent, atBegin, atEnd, beforeCurrent, getNumPages, renderPagination;\n afterCurrent = 2;\n beforeCurrent = 4;\n atBegin = 2;\n atEnd = 2;\n $pagEl = $el.find(\".issues-paginator\");\n getNumPages = function() {\n var numPages;\n numPages = $scope.count / $scope.paginatedBy;\n if (parseInt(numPages, 10) < numPages) {\n numPages = parseInt(numPages, 10) + 1;\n } else {\n numPages = parseInt(numPages, 10);\n }\n return numPages;\n };\n renderPagination = function() {\n var cpage, i, numPages, options, pages, _i;\n numPages = getNumPages();\n if (numPages <= 1) {\n $pagEl.hide();\n return;\n }\n $pagEl.show();\n pages = [];\n options = {};\n options.pages = pages;\n options.showPrevious = $scope.page > 1;\n options.showNext = !($scope.page === numPages);\n cpage = $scope.page;\n for (i = _i = 1; 1 <= numPages ? _i <= numPages : _i >= numPages; i = 1 <= numPages ? ++_i : --_i) {\n if (i === (cpage + afterCurrent) && numPages > (cpage + afterCurrent + atEnd)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i === (cpage - beforeCurrent) && cpage > (atBegin + beforeCurrent)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i > (cpage + afterCurrent) && i <= (numPages - atEnd)) {\n\n } else if (i < (cpage - beforeCurrent) && i > atBegin) {\n\n } else if (i === cpage) {\n pages.push({\n classes: \"active\",\n num: i,\n type: \"page-active\"\n });\n } else {\n pages.push({\n classes: \"page\",\n num: i,\n type: \"page\"\n });\n }\n }\n return $pagEl.html(template(options));\n };\n $scope.$watch(\"issues\", function(value) {\n if (!value) {\n return;\n }\n return renderPagination();\n });\n $el.on(\"click\", \".issues-paginator a.next\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page + 1);\n return $ctrl.loadIssues();\n });\n });\n $el.on(\"click\", \".issues-paginator a.previous\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page - 1);\n return $ctrl.loadIssues();\n });\n });\n return $el.on(\"click\", \".issues-paginator li.page > a\", function(event) {\n var pagenum, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n pagenum = target.data(\"pagenum\");\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", pagenum);\n return $ctrl.loadIssues();\n });\n });\n };\n linkOrdering = function($scope, $el, $attrs, $ctrl) {\n var colHeadElement, currentOrder, icon;\n currentOrder = $ctrl.getUrlFilter(\"orderBy\") || \"created_date\";\n if (currentOrder) {\n icon = startswith(currentOrder, \"-\") ? \"icon-caret-up\" : \"icon-caret-down\";\n colHeadElement = $el.find(\".row.title > div[data-fieldname='\" + (trim(currentOrder, \"-\")) + \"']\");\n colHeadElement.html(\"\" + (colHeadElement.html()) + \"\");\n }\n return $el.on(\"click\", \".row.title > div\", function(event) {\n var finalOrder, newOrder, target;\n target = angular.element(event.currentTarget);\n currentOrder = $ctrl.getUrlFilter(\"orderBy\");\n newOrder = target.data(\"fieldname\");\n finalOrder = currentOrder === newOrder ? \"-\" + newOrder : newOrder;\n return $scope.$apply(function() {\n $ctrl.replaceFilter(\"orderBy\", finalOrder);\n $ctrl.storeFilters();\n return $ctrl.loadIssues().then(function() {\n $el.find(\".row.title > div > span.icon\").remove();\n icon = startswith(finalOrder, \"-\") ? \"icon-caret-up\" : \"icon-caret-down\";\n return target.html(\"\" + (target.html()) + \"\");\n });\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n linkOrdering($scope, $el, $attrs, $ctrl);\n linkPagination($scope, $el, $attrs, $ctrl);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssues\", [\"$log\", \"$tgLocation\", \"$tgTemplate\", IssuesDirective]);\n\n IssuesFiltersDirective = function($log, $location, $rs, $confirm, $loading, $template) {\n var link, template, templateSelected;\n template = $template.get(\"issue/issues-filters.html\", true);\n templateSelected = $template.get(\"issue/issues-filters-selected.html\", true);\n link = function($scope, $el, $attrs) {\n var $ctrl, initializeSelectedFilters, renderFilters, renderSelectedFilters, selectQFilter, selectedFilters, showCategories, showFilters, toggleFilterSelection;\n $ctrl = $el.closest(\".wrapper\").controller();\n selectedFilters = [];\n showFilters = function(title, type) {\n $el.find(\".filters-cats\").hide();\n $el.find(\".filter-list\").removeClass(\"hidden\");\n $el.find(\"h2.breadcrumb\").removeClass(\"hidden\");\n $el.find(\"h2 a.subfilter span.title\").html(title);\n return $el.find(\"h2 a.subfilter span.title\").prop(\"data-type\", type);\n };\n showCategories = function() {\n $el.find(\".filters-cats\").show();\n $el.find(\".filter-list\").addClass(\"hidden\");\n return $el.find(\"h2.breadcrumb\").addClass(\"hidden\");\n };\n initializeSelectedFilters = function(filters) {\n var name, val, values, _i, _len;\n selectedFilters = [];\n for (name in filters) {\n values = filters[name];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n val = values[_i];\n if (val.selected) {\n selectedFilters.push(val);\n }\n }\n }\n return renderSelectedFilters(selectedFilters);\n };\n renderSelectedFilters = function(selectedFilters) {\n var html;\n _.filter(selectedFilters, (function(_this) {\n return function(f) {\n if (f.color) {\n return f.style = \"border-left: 3px solid \" + f.color;\n }\n };\n })(this));\n html = templateSelected({\n filters: selectedFilters\n });\n $el.find(\".filters-applied\").html(html);\n if (selectedFilters.length > 0) {\n return $el.find(\".save-filters\").show();\n } else {\n return $el.find(\".save-filters\").hide();\n }\n };\n renderFilters = function(filters) {\n var html;\n _.filter(filters, (function(_this) {\n return function(f) {\n if (f.color) {\n return f.style = \"border-left: 3px solid \" + f.color;\n }\n };\n })(this));\n html = template({\n filters: filters\n });\n return $el.find(\".filter-list\").html(html);\n };\n toggleFilterSelection = function(type, id) {\n var currentFiltersType, filter, filterId, filters;\n if (type === \"myFilters\") {\n $rs.issues.getMyFilters($scope.projectId).then(function(data) {\n var filters, myFilters;\n myFilters = data;\n filters = myFilters[id];\n filters.page = 1;\n $ctrl.replaceAllFilters(filters);\n $ctrl.storeFilters();\n $ctrl.loadIssues();\n $ctrl.markSelectedFilters($scope.filters, filters);\n return initializeSelectedFilters($scope.filters);\n });\n return null;\n }\n filters = $scope.filters[type];\n filterId = type === 'tags' ? taiga.toString(id) : id;\n filter = _.find(filters, {\n id: filterId\n });\n filter.selected = !filter.selected;\n if (id === null) {\n id = \"null\";\n }\n if (filter.selected) {\n selectedFilters.push(filter);\n $scope.$apply(function() {\n $ctrl.selectFilter(type, id);\n $ctrl.selectFilter(\"page\", 1);\n $ctrl.storeFilters();\n return $ctrl.loadIssues();\n });\n } else {\n selectedFilters = _.reject(selectedFilters, filter);\n $scope.$apply(function() {\n $ctrl.unselectFilter(type, id);\n $ctrl.selectFilter(\"page\", 1);\n $ctrl.storeFilters();\n return $ctrl.loadIssues();\n });\n }\n renderSelectedFilters(selectedFilters);\n currentFiltersType = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (type === currentFiltersType) {\n return renderFilters(_.reject(filters, \"selected\"));\n }\n };\n $scope.$on(\"filters:loaded\", function(ctx, filters) {\n return initializeSelectedFilters(filters);\n });\n selectQFilter = debounceLeading(100, function(value) {\n if (value === void 0) {\n return;\n }\n if (value.length === 0) {\n $ctrl.replaceFilter(\"q\", null);\n $ctrl.storeFilters();\n } else {\n $ctrl.replaceFilter(\"q\", value);\n $ctrl.storeFilters();\n }\n return $ctrl.loadIssues();\n });\n $scope.$watch(\"filtersQ\", selectQFilter);\n $el.on(\"click\", \".filters-cats > ul > li > a\", function(event) {\n var tags, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n tags = $scope.filters[target.data(\"type\")];\n renderFilters(_.reject(tags, \"selected\"));\n return showFilters(target.attr(\"title\"), target.data(\"type\"));\n });\n $el.on(\"click\", \".filters-inner > .filters-step-cat > .breadcrumb > .back\", function(event) {\n event.preventDefault();\n return showCategories($el);\n });\n $el.on(\"click\", \".filters-applied a\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n id = target.data(\"id\") || null;\n type = target.data(\"type\");\n return toggleFilterSelection(type, id);\n });\n $el.on(\"click\", \".filter-list .single-filter\", function(event) {\n var id, target, type;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n target.toggleClass(\"active\");\n id = target.data(\"id\") || null;\n type = target.data(\"type\");\n if (type === \"myFilters\") {\n target.removeClass(\"active\");\n }\n return toggleFilterSelection(type, id);\n });\n $el.on(\"click\", \".filter-list .single-filter .icon-delete\", function(event) {\n var customFilterName, message, target, title;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n customFilterName = target.parent().data('id');\n title = \"Delete custom filter\";\n message = \"the custom filter '\" + customFilterName + \"'\";\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var promise;\n promise = $ctrl.deleteMyFilter(customFilterName);\n promise.then(function() {\n promise = $ctrl.loadMyFilters();\n promise.then(function(filters) {\n finish();\n $scope.filters.myFilters = filters;\n return renderFilters($scope.filters.myFilters);\n });\n return promise.then(null, function() {\n return finish();\n });\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n });\n });\n $el.on(\"click\", \".save-filters\", function(event) {\n event.preventDefault();\n renderFilters($scope.filters[\"myFilters\"]);\n showFilters(\"My filters\", \"myFilters\");\n $el.find('.save-filters').hide();\n $el.find('.my-filter-name').removeClass(\"hidden\");\n return $el.find('.my-filter-name').focus();\n });\n return $el.on(\"keyup\", \".new .my-filter-name\", function(event) {\n var newFilter, promise, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newFilter = target.val();\n $loading.start($el.find(\".new\"));\n promise = $ctrl.saveCurrentFiltersTo(newFilter);\n promise.then(function() {\n var loadPromise;\n loadPromise = $ctrl.loadMyFilters();\n loadPromise.then(function(filters) {\n var currentfilterstype;\n $loading.finish($el.find(\".new\"));\n $scope.filters.myFilters = filters;\n currentfilterstype = $el.find(\"h2 a.subfilter span.title\").prop('data-type');\n if (currentfilterstype === \"myFilters\") {\n renderFilters($scope.filters.myFilters);\n }\n $el.find('.my-filter-name').addClass(\"hidden\");\n return $el.find('.save-filters').show();\n });\n return loadPromise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n return $confirm.notify(\"error\", \"Error loading custom filters\");\n });\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".my-filter-name\").val(newFilter).focus().select();\n return $confirm.notify(\"error\", \"Filter not saved\");\n });\n } else if (event.keyCode === 27) {\n $el.find('.my-filter-name').val('');\n $el.find('.my-filter-name').addClass(\"hidden\");\n return $el.find('.save-filters').show();\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssuesFilters\", [\"$log\", \"$tgLocation\", \"$tgResources\", \"$tgConfirm\", \"$tgLoading\", \"$tgTemplate\", IssuesFiltersDirective]);\n\n IssueStatusInlineEditionDirective = function($repo, $template) {\n\n /*\n Print the status of an Issue and a popover to change it.\n - tg-issue-status-inline-edition: The issue\n \n Example:\n \n div.status(tg-issue-status-inline-edition=\"issue\")\n a.issue-status(href=\"\")\n \n NOTE: This directive need 'issueStatusById' and 'project'.\n */\n var link, selectionTemplate, updateIssueStatus;\n selectionTemplate = $template.get(\"issue/issue-status-inline-edition-selection.html\", true);\n updateIssueStatus = function($el, issue, issueStatusById) {\n var issueStatusDom, issueStatusDomParent, status;\n issueStatusDomParent = $el.find(\".issue-status\");\n issueStatusDom = $el.find(\".issue-status .issue-status-bind\");\n status = issueStatusById[issue.status];\n if (status) {\n issueStatusDom.text(status.name);\n issueStatusDom.prop(\"title\", status.name);\n return issueStatusDomParent.css('color', status.color);\n }\n };\n link = function($scope, $el, $attrs) {\n var $ctrl, issue;\n $ctrl = $el.controller();\n issue = $scope.$eval($attrs.tgIssueStatusInlineEdition);\n $el.on(\"click\", \".issue-status\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n issue.status = target.data(\"status-id\");\n $el.find(\".pop-status\").popover().close();\n updateIssueStatus($el, issue, $scope.issueStatusById);\n return $scope.$apply(function() {\n return $repo.save(issue).then;\n });\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n $el.append(selectionTemplate({\n 'statuses': project.issue_statuses\n }));\n updateIssueStatus($el, issue, $scope.issueStatusById);\n if (project.my_permissions.indexOf(\"modify_issue\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$watch($attrs.tgIssueStatusInlineEdition, (function(_this) {\n return function(val) {\n return updateIssueStatus($el, val, $scope.issueStatusById);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssueStatusInlineEdition\", [\"$tgRepo\", \"$tgTemplate\", IssueStatusInlineEditionDirective]);\n\n IssueAssignedToInlineEditionDirective = function($repo, $rootscope, popoverService) {\n var link, template;\n template = _.template(\"\\\" alt=\\\"<%- name %>\\\"/>\\n
    <%- name %>
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, issue, updateIssue;\n updateIssue = function(issue) {\n var ctx, member;\n ctx = {\n name: \"Unassigned\",\n imgurl: \"/images/unnamed.png\"\n };\n member = $scope.usersById[issue.assigned_to];\n if (member) {\n ctx.imgurl = member.photo;\n ctx.name = member.full_name_display;\n }\n $el.find(\".avatar\").html(template(ctx));\n return $el.find(\".issue-assignedto\").attr('title', ctx.name);\n };\n $ctrl = $el.controller();\n issue = $scope.$eval($attrs.tgIssueAssignedToInlineEdition);\n updateIssue(issue);\n $el.on(\"click\", \".issue-assignedto\", function(event) {\n return $rootscope.$broadcast(\"assigned-to:add\", issue);\n });\n taiga.bindOnce($scope, \"project\", function(project) {\n if (project.my_permissions.indexOf(\"modify_issue\") === -1) {\n $el.unbind(\"click\");\n return $el.find(\"a\").addClass(\"not-clickable\");\n }\n });\n $scope.$on(\"assigned-to:added\", (function(_this) {\n return function(ctx, userId, updatedIssue) {\n if (updatedIssue.id === issue.id) {\n updatedIssue.assigned_to = userId;\n $repo.save(updatedIssue);\n return updateIssue(updatedIssue);\n }\n };\n })(this));\n $scope.$watch($attrs.tgIssueAssignedToInlineEdition, (function(_this) {\n return function(val) {\n return updateIssue(val);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgIssueAssignedToInlineEdition\", [\"$tgRepo\", \"$rootScope\", IssueAssignedToInlineEditionDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/userstories/detail.coffee\n */\n\n(function() {\n var UsClientRequirementButtonDirective, UsStatusButtonDirective, UsStatusDisplayDirective, UsTasksProgressDisplayDirective, UsTeamRequirementButtonDirective, UserStoryDetailController, bindOnce, groupBy, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaUserStories\");\n\n UserStoryDetailController = (function(_super) {\n __extends(UserStoryDetailController, _super);\n\n UserStoryDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function UserStoryDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.usRef = this.params.usref;\n this.scope.sectionName = \"User Story Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.us.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n UserStoryDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"related-tasks:update\", (function(_this) {\n return function() {\n _this.loadUs();\n return _this.scope.tasks = _.clone(_this.scope.tasks, false);\n };\n })(this));\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on userstory\", 1);\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n if (this.scope.project.is_backlog_activated) {\n if (this.scope.us.milestone) {\n ctx.sprint = this.scope.sprint.slug;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-taskboard\", ctx);\n } else {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-backlog\", ctx);\n }\n } else if (this.scope.project.is_kanban_activated) {\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-kanban\", ctx);\n }\n };\n\n UserStoryDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.us_statuses;\n _this.scope.statusById = groupBy(project.us_statuses, function(x) {\n return x.id;\n });\n _this.scope.taskStatusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.pointsById = groupBy(_this.scope.pointsList, function(e) {\n return e.id;\n });\n return project;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadUs = function() {\n return this.rs.userstories.getByRef(this.scope.projectId, this.params.usref).then((function(_this) {\n return function(us) {\n var ctx;\n _this.scope.us = us;\n _this.scope.usId = us.id;\n _this.scope.commentModel = us;\n if (_this.scope.us.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.us.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n if (_this.scope.us.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.us.neighbors.next.ref\n };\n _this.scope.nextUrl = _this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n return us;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadSprint = function() {\n if (this.scope.us.milestone) {\n return this.rs.sprints.get(this.scope.us.project, this.scope.us.milestone).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n return sprint;\n };\n })(this));\n }\n };\n\n UserStoryDetailController.prototype.loadTasks = function() {\n return this.rs.tasks.list(this.scope.projectId, null, this.scope.usId).then((function(_this) {\n return function(tasks) {\n _this.scope.tasks = tasks;\n return tasks;\n };\n })(this));\n };\n\n UserStoryDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadUs().then(function() {\n return _this.q.all([_this.loadSprint(), _this.loadTasks()]);\n });\n };\n })(this));\n };\n\n return UserStoryDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserStoryDetailController\", UserStoryDetailController);\n\n UsStatusDisplayDirective = function($template) {\n var link, template;\n template = $template.get(\"common/components/status-display.html\", true);\n link = function($scope, $el, $attrs) {\n var render;\n render = function(us) {\n var html;\n html = template({\n is_closed: us.is_closed,\n status: $scope.statusById[us.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(us) {\n if (us != null) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsStatusDisplay\", [\"$tgTemplate\", UsStatusDisplayDirective]);\n\n UsTasksProgressDisplayDirective = function($template) {\n var link, template;\n template = $template.get(\"us/us-task-progress.html\", true);\n link = function($scope, $el, $attrs) {\n var render;\n render = function(tasks) {\n var html, progress, totalClosedTasks, totalTasks;\n totalTasks = tasks.length;\n totalClosedTasks = _.filter(tasks, (function(_this) {\n return function(task) {\n return $scope.taskStatusById[task.status].is_closed;\n };\n })(this)).length;\n progress = totalTasks > 0 ? 100 * totalClosedTasks / totalTasks : 0;\n html = template({\n totalTasks: totalTasks,\n totalClosedTasks: totalClosedTasks,\n progress: progress\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(tasks) {\n if (tasks != null) {\n return render(tasks);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsTasksProgressDisplay\", [\"$tgTemplate\", UsTasksProgressDisplayDirective]);\n\n UsStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"us/us-status-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = (function(_this) {\n return function(us) {\n var html, status;\n status = $scope.statusById[us.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(status) {\n var onError, onSuccess, us;\n us = $model.$modelValue.clone();\n us.status = status;\n $.fn.popover().closeAll();\n $model.$setViewValue(us);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n us.revert();\n $model.$setViewValue(us);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var status, target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n status = target.data(\"status-id\");\n return save(status);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", UsStatusButtonDirective]);\n\n UsTeamRequirementButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"us/us-team-requirement-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var canEdit, render, save;\n canEdit = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var ctx, html;\n if (!canEdit() && !us.team_requirement) {\n $el.html(\"\");\n return;\n }\n ctx = {\n canEdit: canEdit(),\n isRequired: us.team_requirement\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(team_requirement) {\n var promise, us;\n us = $model.$modelValue.clone();\n us.team_requirement = team_requirement;\n $model.$setViewValue(us);\n $loading.start($el.find(\"label\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el.find(\"label\"));\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\"label\"));\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n });\n };\n })(this));\n $el.on(\"click\", \".team-requirement\", function(event) {\n var team_requirement;\n if (!canEdit()) {\n return;\n }\n team_requirement = !$model.$modelValue.team_requirement;\n return save(team_requirement);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsTeamRequirementButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", UsTeamRequirementButtonDirective]);\n\n UsClientRequirementButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template) {\n var link, template;\n template = $template.get(\"us/us-client-requirement-button.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var canEdit, render, save;\n canEdit = function() {\n return $scope.project.my_permissions.indexOf(\"modify_us\") !== -1;\n };\n render = function(us) {\n var ctx, html;\n if (!canEdit() && !us.client_requirement) {\n $el.html(\"\");\n return;\n }\n ctx = {\n canEdit: canEdit(),\n isRequired: us.client_requirement\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(client_requirement) {\n var promise, us;\n us = $model.$modelValue.clone();\n us.client_requirement = client_requirement;\n $model.$setViewValue(us);\n $loading.start($el.find(\"label\"));\n promise = $tgrepo.save($model.$modelValue);\n promise.then(function() {\n $loading.finish($el.find(\"label\"));\n return $rootscope.$broadcast(\"history:reload\");\n });\n return promise.then(null, function() {\n $loading.finish($el.find(\"label\"));\n $confirm.notify(\"error\");\n us.revert();\n return $model.$setViewValue(us);\n });\n };\n })(this));\n $el.on(\"click\", \".client-requirement\", function(event) {\n var client_requirement;\n if (!canEdit()) {\n return;\n }\n client_requirement = !$model.$modelValue.client_requirement;\n return save(client_requirement);\n });\n $scope.$watch($attrs.ngModel, function(us) {\n if (us) {\n return render(us);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgUsClientRequirementButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", \"$tgTemplate\", UsClientRequirementButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/tasks/detail.coffee\n */\n\n(function() {\n var TaskDetailController, TaskIsIocaineButtonDirective, TaskStatusButtonDirective, TaskStatusDisplayDirective, groupBy, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n module = angular.module(\"taigaTasks\");\n\n TaskDetailController = (function(_super) {\n __extends(TaskDetailController, _super);\n\n TaskDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function TaskDetailController(scope, rootscope, repo, confirm, rs, params, q, location, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.taskRef = this.params.taskref;\n this.scope.sectionName = \"Task Details\";\n this.initializeEventHandlers();\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.task.subject + \" - \" + _this.scope.project.name);\n return _this.initializeOnDeleteGoToUrl();\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TaskDetailController.prototype.initializeEventHandlers = function() {\n this.scope.$on(\"attachment:create\", (function(_this) {\n return function() {\n _this.analytics.trackEvent(\"attachment\", \"create\", \"create attachment on task\", 1);\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n this.scope.$on(\"attachment:edit\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n return this.scope.$on(\"attachment:delete\", (function(_this) {\n return function() {\n return _this.rootscope.$broadcast(\"history:reload\");\n };\n })(this));\n };\n\n TaskDetailController.prototype.initializeOnDeleteGoToUrl = function() {\n var ctx;\n ctx = {\n project: this.scope.project.slug\n };\n this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project\", ctx);\n if (this.scope.project.is_backlog_activated) {\n if (this.scope.task.milestone) {\n ctx.sprint = this.scope.sprint.slug;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-taskboard\", ctx);\n } else if (this.scope.task.us) {\n ctx.ref = this.scope.us.ref;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n } else if (this.scope.project.is_kanban_activated) {\n if (this.scope.us) {\n ctx.ref = this.scope.us.ref;\n return this.scope.onDeleteGoToUrl = this.navUrls.resolve(\"project-userstories-detail\", ctx);\n }\n }\n };\n\n TaskDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.statusList = project.task_statuses;\n _this.scope.statusById = groupBy(project.task_statuses, function(x) {\n return x.id;\n });\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n TaskDetailController.prototype.loadTask = function() {\n return this.rs.tasks.getByRef(this.scope.projectId, this.params.taskref).then((function(_this) {\n return function(task) {\n var ctx;\n _this.scope.task = task;\n _this.scope.taskId = task.id;\n _this.scope.commentModel = task;\n if (_this.scope.task.neighbors.previous.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.task.neighbors.previous.ref\n };\n _this.scope.previousUrl = _this.navUrls.resolve(\"project-tasks-detail\", ctx);\n }\n if (_this.scope.task.neighbors.next.ref != null) {\n ctx = {\n project: _this.scope.project.slug,\n ref: _this.scope.task.neighbors.next.ref\n };\n _this.scope.nextUrl = _this.navUrls.resolve(\"project-tasks-detail\", ctx);\n }\n return task;\n };\n })(this));\n };\n\n TaskDetailController.prototype.loadSprint = function() {\n if (this.scope.task.milestone) {\n return this.rs.sprints.get(this.scope.task.project, this.scope.task.milestone).then((function(_this) {\n return function(sprint) {\n _this.scope.sprint = sprint;\n return sprint;\n };\n })(this));\n }\n };\n\n TaskDetailController.prototype.loadUserStory = function() {\n if (this.scope.task.user_story) {\n return this.rs.userstories.get(this.scope.task.project, this.scope.task.user_story).then((function(_this) {\n return function(us) {\n _this.scope.us = us;\n return us;\n };\n })(this));\n }\n };\n\n TaskDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadTask().then(function() {\n return _this.q.all([_this.loadSprint(), _this.loadUserStory()]);\n });\n };\n })(this));\n };\n\n return TaskDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TaskDetailController\", TaskDetailController);\n\n TaskStatusDisplayDirective = function($template) {\n var link, template;\n template = $template.get(\"common/components/status-display.html\", true);\n link = function($scope, $el, $attrs) {\n var render;\n render = function(task) {\n var html;\n html = template({\n status: $scope.statusById[task.status]\n });\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(task) {\n if (task != null) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskStatusDisplay\", [\"$tgTemplate\", TaskStatusDisplayDirective]);\n\n TaskStatusButtonDirective = function($rootScope, $repo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    clickable<% }%>\\\">\\n \\\">\\n <%- status.name %>\\n <% if(editable){ %><% }%>\\n status\\n\\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_task\") !== -1;\n };\n render = (function(_this) {\n return function(task) {\n var html, status;\n status = $scope.statusById[task.status];\n html = template({\n status: status,\n statuses: $scope.statusList,\n editable: isEditable()\n });\n return $el.html(html);\n };\n })(this);\n save = $qqueue.bindAdd((function(_this) {\n return function(status) {\n var onError, onSuccess, task;\n task = $model.$modelValue.clone();\n task.status = status;\n $model.$setViewValue(task);\n onSuccess = function() {\n $confirm.notify(\"success\");\n $rootScope.$broadcast(\"history:reload\");\n return $loading.finish($el.find(\".level-name\"));\n };\n onError = function() {\n $confirm.notify(\"error\");\n task.revert();\n $model.$setViewValue(task);\n return $loading.finish($el.find(\".level-name\"));\n };\n $loading.start($el.find(\".level-name\"));\n return $repo.save($model.$modelValue).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"click\", \".status-data\", function(event) {\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n return $el.find(\".pop-status\").popover().open();\n });\n $el.on(\"click\", \".status\", function(event) {\n var target;\n event.preventDefault();\n event.stopPropagation();\n if (!isEditable()) {\n return;\n }\n target = angular.element(event.currentTarget);\n $.fn.popover().closeAll();\n return save(target.data(\"status-id\"));\n });\n $scope.$watch($attrs.ngModel, function(task) {\n if (task) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskStatusButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", TaskStatusButtonDirective]);\n\n TaskIsIocaineButtonDirective = function($rootscope, $tgrepo, $confirm, $loading, $qqueue) {\n var link, template;\n template = _.template(\"
    \\n \\n \\n
    \");\n link = function($scope, $el, $attrs, $model) {\n var isEditable, render, save;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_task\") !== -1;\n };\n render = function(task) {\n var ctx, html;\n if (!isEditable() && !task.is_iocaine) {\n $el.html(\"\");\n return;\n }\n ctx = {\n isIocaine: task.is_iocaine,\n isEditable: isEditable()\n };\n html = template(ctx);\n return $el.html(html);\n };\n save = $qqueue.bindAdd((function(_this) {\n return function(is_iocaine) {\n var promise, task;\n task = $model.$modelValue.clone();\n task.is_iocaine = is_iocaine;\n $model.$setViewValue(task);\n $loading.start($el.find('label'));\n promise = $tgrepo.save(task);\n promise.then(function() {\n $confirm.notify(\"success\");\n return $rootscope.$broadcast(\"history:reload\");\n });\n promise.then(null, function() {\n task.revert();\n $model.$setViewValue(task);\n return $confirm.notify(\"error\");\n });\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('label'));\n });\n };\n })(this));\n $el.on(\"click\", \".is-iocaine\", function(event) {\n var is_iocaine;\n if (!isEditable()) {\n return;\n }\n is_iocaine = !$model.$modelValue.is_iocaine;\n return save(is_iocaine);\n });\n $scope.$watch($attrs.ngModel, function(task) {\n if (task) {\n return render(task);\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgTaskIsIocaineButton\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgQqueue\", TaskIsIocaineButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/team/main.coffee\n */\n\n(function() {\n var LeaveProjectDirective, TeamController, TeamFiltersDirective, TeamMemberCurrentUserDirective, TeamMemberStatsDirective, TeamMembersDirective, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n module = angular.module(\"taigaTeam\");\n\n TeamController = (function(_super) {\n __extends(TeamController, _super);\n\n TeamController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$q\", \"$location\", \"$tgNavUrls\", \"$appTitle\", \"$tgAuth\", \"tgLoader\"];\n\n function TeamController(scope, rootscope, repo, rs, params, q, location, navUrls, appTitle, auth, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.auth = auth;\n this.scope.sectionName = \"Team\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Team - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n TeamController.prototype.setRole = function(role) {\n if (role) {\n return this.scope.filtersRole = role;\n } else {\n return this.scope.filtersRole = \"\";\n }\n };\n\n TeamController.prototype.loadMembers = function() {\n return this.rs.memberships.list(this.scope.projectId, {}, false).then((function(_this) {\n return function(data) {\n var currentUser, membership, _i, _len, _ref;\n currentUser = _this.auth.getUser();\n if (currentUser.photo == null) {\n currentUser.photo = \"/images/unnamed.png\";\n }\n _this.scope.currentUser = _.find(data, function(membership) {\n return membership.user === currentUser.id;\n });\n _this.scope.totals = {};\n _.forEach(data, function(membership) {\n return _this.scope.totals[membership.user] = 0;\n });\n _this.scope.memberships = _.filter(data, function(membership) {\n if (membership.user && membership.user !== currentUser.id && membership.is_user_active) {\n return membership;\n }\n });\n _ref = _this.scope.memberships;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n membership = _ref[_i];\n if (membership.photo == null) {\n membership.photo = \"/images/unnamed.png\";\n }\n }\n return data;\n };\n })(this));\n };\n\n TeamController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.issuesEnabled = project.is_issues_activated;\n _this.scope.tasksEnabled = project.is_kanban_activated || project.is_backlog_activated;\n _this.scope.wikiEnabled = project.is_wiki_activated;\n return project;\n };\n })(this));\n };\n\n TeamController.prototype.loadMemberStats = function() {\n return this.rs.projects.memberStats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n var totals;\n totals = {};\n _.forEach(_this.scope.totals, function(total, userId) {\n var vals;\n vals = _.map(stats, function(memberStats, statsKey) {\n return memberStats[userId];\n });\n total = _.reduce(vals, function(sum, el) {\n return sum + el;\n });\n return _this.scope.totals[userId] = total;\n });\n _this.scope.stats = _this.processStats(stats);\n return _this.scope.stats.totals = _this.scope.totals;\n };\n })(this));\n };\n\n TeamController.prototype.processStat = function(stat) {\n var max, min, singleStat;\n max = _.max(stat);\n min = _.min(stat);\n singleStat = _.map(stat, function(value, key) {\n if (value === min) {\n return [key, 0.1];\n }\n if (value === max) {\n return [key, 1];\n }\n return [key, (value * 0.5) / max];\n });\n singleStat = _.object(singleStat);\n return singleStat;\n };\n\n TeamController.prototype.processStats = function(stats) {\n var key, value;\n for (key in stats) {\n value = stats[key];\n stats[key] = this.processStat(value);\n }\n return stats;\n };\n\n TeamController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.loadMembers().then(function() {\n return _this.loadMemberStats();\n });\n };\n })(this));\n };\n\n return TeamController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"TeamController\", TeamController);\n\n TeamFiltersDirective = function() {\n return {\n templateUrl: \"team/team-filter.html\"\n };\n };\n\n module.directive(\"tgTeamFilters\", [TeamFiltersDirective]);\n\n TeamMemberStatsDirective = function() {\n return {\n templateUrl: \"team/team-member-stats.html\",\n scope: {\n stats: \"=\",\n userId: \"=user\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamMemberStats\", TeamMemberStatsDirective);\n\n TeamMemberCurrentUserDirective = function() {\n return {\n templateUrl: \"team/team-member-current-user.html\",\n scope: {\n projectId: \"=projectid\",\n currentUser: \"=currentuser\",\n stats: \"=\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamCurrentUser\", TeamMemberCurrentUserDirective);\n\n TeamMembersDirective = function() {\n var template;\n template = \"team/team-members.html\";\n return {\n templateUrl: template,\n scope: {\n memberships: \"=\",\n filtersQ: \"=filtersq\",\n filtersRole: \"=filtersrole\",\n stats: \"=\",\n issuesEnabled: \"=issuesenabled\",\n tasksEnabled: \"=tasksenabled\",\n wikiEnabled: \"=wikienabled\"\n }\n };\n };\n\n module.directive(\"tgTeamMembers\", TeamMembersDirective);\n\n LeaveProjectDirective = function($repo, $confirm, $location, $rs, $navurls) {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.leave = function() {\n return $confirm.ask(\"Leave this project\", \"Are you sure you want to leave the project?\").then((function(_this) {\n return function(finish) {\n var promise;\n promise = $rs.projects.leave($attrs.projectid);\n promise.then(function() {\n finish();\n $confirm.notify(\"success\");\n return $location.path($navurls.resolve(\"home\"));\n });\n return promise.then(null, function(response) {\n finish();\n return $confirm.notify('error', response.data._error_message);\n });\n };\n })(this));\n };\n };\n return {\n scope: {},\n templateUrl: \"team/leave-project.html\",\n link: link\n };\n };\n\n module.directive(\"tgLeaveProject\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", \"$tgResources\", \"$tgNavUrls\", LeaveProjectDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki/detail.coffee\n */\n\n(function() {\n var EditableWikiContentDirective, WikiDetailController, WikiSummaryDirective, bindOnce, debounce, groupBy, mixOf, module, taiga, unslugify,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n unslugify = this.taiga.unslugify;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaWiki\");\n\n WikiDetailController = (function(_super) {\n __extends(WikiDetailController, _super);\n\n WikiDetailController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgModel\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$filter\", \"$log\", \"$appTitle\", \"$tgNavUrls\", \"$tgAnalytics\", \"tgLoader\"];\n\n function WikiDetailController(scope, rootscope, repo, model, confirm, rs, params, q, location, filter, log, appTitle, navUrls, analytics, tgLoader) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.model = model;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.filter = filter;\n this.log = log;\n this.appTitle = appTitle;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.scope.projectSlug = this.params.pslug;\n this.scope.wikiSlug = this.params.slug;\n this.scope.sectionName = \"Wiki\";\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Wiki - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n WikiDetailController.prototype.loadProject = function() {\n return this.rs.projects.getBySlug(this.params.pslug).then((function(_this) {\n return function(project) {\n _this.scope.projectId = project.id;\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.membersById = groupBy(project.memberships, function(x) {\n return x.user;\n });\n return project;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadWiki = function() {\n var promise;\n promise = this.rs.wiki.getBySlug(this.scope.projectId, this.params.slug);\n promise.then((function(_this) {\n return function(wiki) {\n _this.scope.wiki = wiki;\n _this.scope.wikiId = wiki.id;\n return _this.scope.wiki;\n };\n })(this));\n return promise.then(null, (function(_this) {\n return function(xhr) {\n var data;\n _this.scope.wikiId = null;\n if (_this.scope.project.my_permissions.indexOf(\"add_wiki_page\") === -1) {\n return null;\n }\n data = {\n project: _this.scope.projectId,\n slug: _this.scope.wikiSlug,\n content: \"\"\n };\n _this.scope.wiki = _this.model.make_model(\"wiki\", data);\n return _this.scope.wiki;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadWikiLinks = function() {\n return this.rs.wiki.listLinks(this.scope.projectId).then((function(_this) {\n return function(wikiLinks) {\n return _this.scope.wikiLinks = wikiLinks;\n };\n })(this));\n };\n\n WikiDetailController.prototype.loadInitialData = function() {\n var promise;\n promise = this.loadProject();\n return promise.then((function(_this) {\n return function(project) {\n _this.fillUsersAndRoles(project.users, project.roles);\n return _this.q.all([_this.loadWikiLinks(), _this.loadWiki()]);\n };\n })(this));\n };\n\n WikiDetailController.prototype[\"delete\"] = function() {\n var message, title;\n title = \"Delete Wiki Page\";\n message = unslugify(this.scope.wiki.slug);\n return this.confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n var ctx;\n finish();\n ctx = {\n project: _this.scope.projectSlug\n };\n _this.location.path(_this.navUrls.resolve(\"project-wiki\", ctx));\n return _this.confirm.notify(\"success\");\n };\n onError = function() {\n finish(false);\n return _this.confirm.notify(\"error\");\n };\n return _this.repo.remove(_this.scope.wiki).then(onSuccess, onError);\n };\n })(this));\n };\n\n return WikiDetailController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"WikiDetailController\", WikiDetailController);\n\n WikiSummaryDirective = function($log, $template) {\n var link, template;\n template = $template.get(\"wiki/wiki-summary.html\", true);\n link = function($scope, $el, $attrs, $model) {\n var render;\n render = function(wiki) {\n var ctx, html, user;\n if ($scope.usersById == null) {\n $log.error(\"WikiSummaryDirective requires userById set in scope.\");\n } else {\n user = $scope.usersById[wiki.last_modifier];\n }\n if (user === void 0) {\n user = {\n name: \"unknown\",\n imgUrl: \"/images/unnamed.png\"\n };\n } else {\n user = {\n name: user.full_name_display,\n imgUrl: user.photo\n };\n }\n ctx = {\n totalEditions: wiki.editions,\n lastModifiedDate: moment(wiki.modified_date).format(\"DD MMM YYYY HH:mm\"),\n user: user\n };\n html = template(ctx);\n return $el.html(html);\n };\n $scope.$watch($attrs.ngModel, function(wikiPage) {\n if (!wikiPage) {\n return;\n }\n return render(wikiPage);\n });\n $scope.$on(\"wiki:edit\", function(event, wikiPage) {\n return render(wikiPage);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgWikiSummary\", [\"$log\", \"$tgTemplate\", WikiSummaryDirective]);\n\n EditableWikiContentDirective = function($window, $document, $repo, $confirm, $loading, $location, $navUrls, $analytics, $qqueue) {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var cancelEdition, disableEdition, getSelectedText, isEditable, save, switchToEditMode, switchToReadMode;\n isEditable = function() {\n return $scope.project.my_permissions.indexOf(\"modify_wiki_page\") !== -1;\n };\n switchToEditMode = function() {\n $el.find('.edit-wiki-content').show();\n $el.find('.view-wiki-content').hide();\n return $el.find('textarea').focus();\n };\n switchToReadMode = function() {\n $el.find('.edit-wiki-content').hide();\n return $el.find('.view-wiki-content').show();\n };\n disableEdition = function() {\n $el.find(\".view-wiki-content .edit\").remove();\n return $el.find(\".edit-wiki-content\").remove();\n };\n cancelEdition = function() {\n var ctx;\n if (!$scope.wiki.html) {\n return;\n }\n if ($scope.wiki.id) {\n $scope.$apply((function(_this) {\n return function() {\n return $scope.wiki.revert();\n };\n })(this));\n return switchToReadMode();\n } else {\n ctx = {\n project: $scope.projectSlug\n };\n return $location.path($navUrls.resolve(\"project-wiki\", ctx));\n }\n };\n getSelectedText = function() {\n if ($window.getSelection) {\n return $window.getSelection().toString();\n } else if ($document.selection) {\n return $document.selection.createRange().text;\n }\n return null;\n };\n save = $qqueue.bindAdd(function(wiki) {\n var onError, onSuccess, promise;\n onSuccess = function(wikiPage) {\n if (wiki.id == null) {\n $analytics.trackEvent(\"wikipage\", \"create\", \"create wiki page\", 1);\n }\n $scope.wiki = wikiPage;\n $model.setModelValue = wiki;\n $confirm.notify(\"success\");\n switchToReadMode();\n return $scope.$broadcast(\"wiki:edit\", wikiPage);\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n $loading.start($el.find('.save-container'));\n if (wiki.id != null) {\n promise = $repo.save(wiki).then(onSuccess, onError);\n } else {\n promise = $repo.create(\"wiki\", wiki).then(onSuccess, onError);\n }\n return promise[\"finally\"](function() {\n return $loading.finish($el.find('.save-container'));\n });\n });\n $el.on(\"mousedown\", \".view-wiki-content\", function(event) {\n var target;\n target = angular.element(event.target);\n if (target.is('pre')) {\n return target.data(\"scroll-pos\", target[0].scrollLeft);\n }\n });\n $el.on(\"mouseup\", \".view-wiki-content\", function(event) {\n var prevPos, target;\n target = angular.element(event.target);\n if (!isEditable()) {\n return;\n }\n if (target.is('a')) {\n return;\n }\n if (getSelectedText()) {\n return;\n }\n if (target.is('pre')) {\n prevPos = target.data(\"scroll-pos\");\n target.data(\"scroll-pos\", null);\n if (prevPos !== target[0].scrollLeft) {\n return;\n }\n }\n return switchToEditMode();\n });\n $el.on(\"click\", \".save\", debounce(2000, function() {\n return save($scope.wiki);\n }));\n $el.on(\"click\", \".cancel\", function() {\n return cancelEdition();\n });\n $el.on(\"keydown\", \"textarea\", function(event) {\n if (event.keyCode === 27) {\n return cancelEdition();\n }\n });\n $scope.$watch($attrs.ngModel, function(wikiPage) {\n if (!wikiPage) {\n return;\n }\n $scope.wiki = wikiPage;\n if (isEditable()) {\n $el.addClass('editable');\n if (wikiPage.id == null) {\n return switchToEditMode();\n }\n } else {\n return disableEdition();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\",\n templateUrl: \"wiki/editable-wiki-content.html\"\n };\n };\n\n module.directive(\"tgEditableWikiContent\", [\"$window\", \"$document\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAnalytics\", \"$tgQqueue\", EditableWikiContentDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/wiki/detail.coffee\n */\n\n(function() {\n var WikiNavDirective, bindOnce, groupBy, mixOf, module, slugify, taiga, unslugify;\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n slugify = this.taiga.slugify;\n\n unslugify = this.taiga.slugify;\n\n module = angular.module(\"taigaWiki\");\n\n WikiNavDirective = function($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $loading, $template) {\n var link, template;\n template = $template.get(\"wiki/wiki-nav.html\", true);\n link = function($scope, $el, $attrs) {\n var $ctrl, render;\n $ctrl = $el.controller();\n if ($attrs.ngModel == null) {\n return $log.error(\"WikiNavDirective: no ng-model attr is defined\");\n }\n render = function(wikiLinks) {\n var addWikiLinkPermission, deleteWikiLinkPermission, html;\n addWikiLinkPermission = $scope.project.my_permissions.indexOf(\"add_wiki_link\") > -1;\n deleteWikiLinkPermission = $scope.project.my_permissions.indexOf(\"delete_wiki_link\") > -1;\n html = template({\n wikiLinks: wikiLinks,\n projectSlug: $scope.projectSlug,\n addWikiLinkPermission: addWikiLinkPermission,\n deleteWikiLinkPermission: deleteWikiLinkPermission\n });\n $el.off();\n $el.html(html);\n $el.on(\"click\", \".wiki-link .link-title\", function(event) {\n var linkId, linkSlug, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n linkId = target.parents('.wiki-link').data('id');\n linkSlug = $scope.wikiLinks[linkId].href;\n return $scope.$apply(function() {\n var ctx;\n ctx = {\n project: $scope.projectSlug,\n slug: linkSlug\n };\n return $location.path($navUrls.resolve(\"project-wiki-page\", ctx));\n });\n });\n $el.on(\"click\", \".add-button\", function(event) {\n event.preventDefault();\n $el.find(\".new\").removeClass(\"hidden\");\n $el.find(\".new input\").focus();\n return $el.find(\".add-button\").hide();\n });\n $el.on(\"click\", \".wiki-link .icon-delete\", function(event) {\n var linkId, message, target, title;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n linkId = target.parents('.wiki-link').data('id');\n title = \"Delete Wiki Link\";\n message = $scope.wikiLinks[linkId].title;\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var promise;\n promise = $tgrepo.remove($scope.wikiLinks[linkId]);\n promise.then(function() {\n promise = $ctrl.loadWikiLinks();\n promise.then(function() {\n finish();\n return render($scope.wikiLinks);\n });\n return promise.then(null, function() {\n return finish();\n });\n });\n return promise.then(null, function() {\n finish(false);\n return $confirm.notify(\"error\");\n });\n };\n })(this));\n });\n return $el.on(\"keyup\", \".new input\", function(event) {\n var newLink, promise, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newLink = target.val();\n $loading.start($el.find(\".new\"));\n promise = $tgrepo.create(\"wiki-links\", {\n project: $scope.projectId,\n title: newLink,\n href: slugify(newLink)\n });\n promise.then(function() {\n var loadPromise;\n $analytics.trackEvent(\"wikilink\", \"create\", \"create wiki link\", 1);\n loadPromise = $ctrl.loadWikiLinks();\n loadPromise.then(function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n $el.find(\".add-button\").show();\n return render($scope.wikiLinks);\n });\n return loadPromise.then(null, function() {\n $loading.finish($el.find(\".new\"));\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n $el.find(\".add-button\").show();\n return $confirm.notify(\"error\", \"Error loading wiki links\");\n });\n });\n return promise.then(null, function(error) {\n var _ref;\n $loading.finish($el.find(\".new\"));\n $el.find(\".new input\").val(newLink);\n $el.find(\".new input\").focus().select();\n if ((error != null ? (_ref = error.__all__) != null ? _ref[0] : void 0 : void 0) != null) {\n return $confirm.notify(\"error\", \"The link already exists\");\n } else {\n return $confirm.notify(\"error\");\n }\n });\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new input\").val('');\n return $el.find(\".add-button\").show();\n }\n });\n };\n return bindOnce($scope, $attrs.ngModel, render);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgWikiNav\", [\"$tgRepo\", \"$log\", \"$tgLocation\", \"$tgConfirm\", \"$tgNavUrls\", \"$tgAnalytics\", \"$tgLoading\", \"$tgTemplate\", WikiNavDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/lightboxes.coffee\n */\n\n(function() {\n var CreateMembersDirective, MAX_MEMBERSHIP_FIELDSETS, debounce, module, taiga;\n\n taiga = this.taiga;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaKanban\");\n\n MAX_MEMBERSHIP_FIELDSETS = 4;\n\n CreateMembersDirective = function($rs, $rootScope, $confirm, $loading, lightboxService) {\n var extraTextTemplate, link, template;\n extraTextTemplate = \"
    \\n \\n
    \";\n template = _.template(\"
    \\n
    \\n data-required=\\\"true\\\" <% } %> data-type=\\\"email\\\" />\\n
    \\n
    \\n \\n \\n
    \\n
    \");\n link = function($scope, $el, $attrs) {\n var createFieldSet, resetForm, submit, submitButton;\n createFieldSet = function(required) {\n var ctx;\n if (required == null) {\n required = true;\n }\n ctx = {\n roleList: $scope.roles,\n required: required\n };\n return template(ctx);\n };\n resetForm = function() {\n var fieldSet, invitations;\n $el.find(\"form textarea\").remove(\"\");\n $el.find(\"form .add-member-wrapper\").remove();\n invitations = $el.find(\".add-member-forms\");\n invitations.html(extraTextTemplate);\n fieldSet = createFieldSet();\n return invitations.prepend(fieldSet);\n };\n $scope.$on(\"membersform:new\", function() {\n resetForm();\n return lightboxService.open($el);\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $el.on(\"click\", \".delete-fieldset\", function(event) {\n var fieldSet, lastActionButton, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n fieldSet = target.closest('.add-member-wrapper');\n fieldSet.remove();\n lastActionButton = $el.find(\"fieldset:last > a\");\n if (lastActionButton.hasClass(\"icon-delete delete-fieldset\")) {\n return lastActionButton.removeClass(\"icon-delete delete-fieldset\").addClass(\"icon-plus add-fieldset\");\n }\n });\n $el.on(\"click\", \".add-fieldset\", function(event) {\n var fieldSet, newFieldSet, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n fieldSet = target.closest('.add-member-wrapper');\n target.removeClass(\"icon-plus add-fieldset\").addClass(\"icon-delete delete-fieldset\");\n newFieldSet = createFieldSet(false);\n fieldSet.after(newFieldSet);\n if ($el.find(\".add-member-wrapper\").length === MAX_MEMBERSHIP_FIELDSETS) {\n return $el.find(\".add-member-wrapper fieldset:last > a\").removeClass(\"icon-plus add-fieldset\").addClass(\"icon-delete delete-fieldset\");\n }\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var form, invitation_extra_text, invitations, memberWrappers, onError, onSuccess;\n event.preventDefault();\n $loading.start(submitButton);\n onSuccess = function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n $confirm.notify(\"success\");\n return $rootScope.$broadcast(\"membersform:new:success\");\n };\n onError = function(data) {\n $loading.finish(submitButton);\n lightboxService.close($el);\n $confirm.notify(\"error\");\n return $rootScope.$broadcast(\"membersform:new:error\");\n };\n form = $el.find(\"form\").checksley();\n form.destroy();\n form.initialize();\n if (!form.validate()) {\n return;\n }\n memberWrappers = $el.find(\"form .add-member-wrapper\");\n memberWrappers = _.filter(memberWrappers, function(mw) {\n return angular.element(mw).find(\"input\").hasClass('checksley-ok');\n });\n invitations = _.map(memberWrappers, function(mw) {\n var email, memberWrapper, role;\n memberWrapper = angular.element(mw);\n email = memberWrapper.find(\"input\");\n role = memberWrapper.find(\"select\");\n return {\n email: email.val(),\n role_id: role.val()\n };\n });\n if (invitations.length) {\n invitation_extra_text = $el.find(\"form textarea\").val();\n return $rs.memberships.bulkCreateMemberships($scope.project.id, invitations, invitation_extra_text).then(onSuccess, onError);\n }\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateMembers\", [\"$tgResources\", \"$rootScope\", \"$tgConfirm\", \"$tgLoading\", \"lightboxService\", CreateMembersDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/memberships.coffee\n */\n\n(function() {\n var MembershipsController, MembershipsDirective, MembershipsRowActionsDirective, MembershipsRowAdminCheckboxDirective, MembershipsRowAvatarDirective, MembershipsRowRoleSelectorDirective, bindMethods, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaAdmin\");\n\n MembershipsController = (function(_super) {\n __extends(MembershipsController, _super);\n\n MembershipsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAnalytics\", \"$appTitle\"];\n\n function MembershipsController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, analytics, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.analytics = analytics;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Manage Members\";\n this.scope.project = {};\n this.scope.filters = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Membership - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"membersform:new:success\", (function(_this) {\n return function() {\n _this.loadMembers();\n return _this.analytics.trackEvent(\"membership\", \"create\", \"create memberships on admin\", 1);\n };\n })(this));\n }\n\n MembershipsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n MembershipsController.prototype.loadMembers = function() {\n var httpFilters;\n httpFilters = this.getUrlFilters();\n return this.rs.memberships.list(this.scope.projectId, httpFilters).then((function(_this) {\n return function(data) {\n _this.scope.memberships = _.filter(data.models, function(membership) {\n return membership.user === null || membership.is_user_active;\n });\n _this.scope.page = data.current;\n _this.scope.count = data.count;\n _this.scope.paginatedBy = data.paginatedBy;\n return data;\n };\n })(this));\n };\n\n MembershipsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadMembers();\n };\n })(this));\n };\n\n MembershipsController.prototype.getUrlFilters = function() {\n var filters;\n filters = _.pick(this.location.search(), \"page\");\n if (!filters.page) {\n filters.page = 1;\n }\n return filters;\n };\n\n MembershipsController.prototype.addNewMembers = function() {\n return this.rootscope.$broadcast(\"membersform:new\");\n };\n\n return MembershipsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"MembershipsController\", MembershipsController);\n\n MembershipsDirective = function($template) {\n var link, linkPagination, template;\n template = $template.get(\"admin/admin-membership-paginator.html\", true);\n linkPagination = function($scope, $el, $attrs, $ctrl) {\n var $pagEl, afterCurrent, atBegin, atEnd, beforeCurrent, getNumPages, renderPagination;\n afterCurrent = 2;\n beforeCurrent = 4;\n atBegin = 2;\n atEnd = 2;\n $pagEl = $el.find(\".memberships-paginator\");\n getNumPages = function() {\n var numPages;\n numPages = $scope.count / $scope.paginatedBy;\n if (parseInt(numPages, 10) < numPages) {\n numPages = parseInt(numPages, 10) + 1;\n } else {\n numPages = parseInt(numPages, 10);\n }\n return numPages;\n };\n renderPagination = function() {\n var cpage, i, numPages, options, pages, _i;\n numPages = getNumPages();\n if (numPages <= 1) {\n $pagEl.hide();\n return;\n }\n pages = [];\n options = {};\n options.pages = pages;\n options.showPrevious = $scope.page > 1;\n options.showNext = !($scope.page === numPages);\n cpage = $scope.page;\n for (i = _i = 1; 1 <= numPages ? _i <= numPages : _i >= numPages; i = 1 <= numPages ? ++_i : --_i) {\n if (i === (cpage + afterCurrent) && numPages > (cpage + afterCurrent + atEnd)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i === (cpage - beforeCurrent) && cpage > (atBegin + beforeCurrent)) {\n pages.push({\n classes: \"dots\",\n type: \"dots\"\n });\n } else if (i > (cpage + afterCurrent) && i <= (numPages - atEnd)) {\n\n } else if (i < (cpage - beforeCurrent) && i > atBegin) {\n\n } else if (i === cpage) {\n pages.push({\n classes: \"active\",\n num: i,\n type: \"page-active\"\n });\n } else {\n pages.push({\n classes: \"page\",\n num: i,\n type: \"page\"\n });\n }\n }\n return $pagEl.html(template(options));\n };\n $scope.$watch(\"memberships\", function(value) {\n if (!value) {\n return;\n }\n return renderPagination();\n });\n $el.on(\"click\", \".memberships-paginator a.next\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page + 1);\n return $ctrl.loadMembers();\n });\n });\n $el.on(\"click\", \".memberships-paginator a.previous\", function(event) {\n event.preventDefault();\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", $scope.page - 1);\n return $ctrl.loadMembers();\n });\n });\n return $el.on(\"click\", \".memberships-paginator li.page > a\", function(event) {\n var pagenum, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n pagenum = target.data(\"pagenum\");\n return $scope.$apply(function() {\n $ctrl.selectFilter(\"page\", pagenum);\n return $ctrl.loadMembers();\n });\n });\n };\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n linkPagination($scope, $el, $attrs, $ctrl);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMemberships\", [\"$tgTemplate\", MembershipsDirective]);\n\n MembershipsRowAvatarDirective = function($log, $template) {\n var link, template;\n template = $template.get(\"admin/memberships-row-avatar.html\", true);\n link = function($scope, $el, $attrs) {\n var member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n full_name: member.full_name ? member.full_name : \"\",\n email: member.user_email ? member.user_email : member.email,\n imgurl: member.photo ? member.photo : \"/images/unnamed.png\"\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowAvatar == null) {\n return $log.error(\"MembershipsRowAvatarDirective: the directive need a member\");\n }\n member = $scope.$eval($attrs.tgMembershipsRowAvatar);\n render(member);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowAvatar\", [\"$log\", \"$tgTemplate\", MembershipsRowAvatarDirective]);\n\n MembershipsRowAdminCheckboxDirective = function($log, $repo, $confirm, $template) {\n var link, template;\n template = $template.get(\"admin/admin-memberships-row-checkbox.html\", true);\n link = function($scope, $el, $attrs) {\n var html, member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n inputId: \"is-admin-\" + member.id\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowAdminCheckbox == null) {\n return $log.error(\"MembershipsRowAdminCheckboxDirective: the directive need a member\");\n }\n member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox);\n html = render(member);\n if (member.is_owner) {\n $el.find(\":checkbox\").prop(\"checked\", true);\n }\n $el.on(\"click\", \":checkbox\", (function(_this) {\n return function(event) {\n var onError, onSuccess, target;\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function(data) {\n member.revert();\n $el.find(\":checkbox\").prop(\"checked\", member.is_owner);\n return $confirm.notify(\"error\", data.is_owner[0]);\n };\n target = angular.element(event.currentTarget);\n member.is_owner = target.prop(\"checked\");\n return $repo.save(member).then(onSuccess, onError);\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowAdminCheckbox\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", \"$tgTemplate\", MembershipsRowAdminCheckboxDirective]);\n\n MembershipsRowRoleSelectorDirective = function($log, $repo, $confirm) {\n var link, template;\n template = _.template(\"\");\n link = function($scope, $el, $attrs) {\n var $ctrl, html, member, render;\n render = function(member) {\n var ctx, html;\n ctx = {\n roleList: $scope.roles,\n selectedRole: member.role\n };\n html = template(ctx);\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowRoleSelector == null) {\n return $log.error(\"MembershipsRowRoleSelectorDirective: the directive need a member\");\n }\n $ctrl = $el.controller();\n member = $scope.$eval($attrs.tgMembershipsRowRoleSelector);\n html = render(member);\n $el.on(\"click\", \"select\", (function(_this) {\n return function(event) {\n var newRole, onError, onSuccess, target;\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n target = angular.element(event.currentTarget);\n newRole = parseInt(target.val(), 10);\n if (member.role !== newRole) {\n member.role = newRole;\n return $repo.save(member).then(onSuccess, onError);\n }\n };\n })(this));\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowRoleSelector\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", MembershipsRowRoleSelectorDirective]);\n\n MembershipsRowActionsDirective = function($log, $repo, $rs, $confirm) {\n var activedTemplate, link, pendingTemplate;\n activedTemplate = _.template(\"
    \\n Active\\n
    \\n\\n \\n\");\n pendingTemplate = _.template(\"\\n Pending\\n \\n\\n\\n \\n\");\n link = function($scope, $el, $attrs) {\n var $ctrl, member, render;\n render = function(member) {\n var html;\n if (member.user) {\n html = activedTemplate();\n } else {\n html = pendingTemplate();\n }\n return $el.html(html);\n };\n if ($attrs.tgMembershipsRowActions == null) {\n return $log.error(\"MembershipsRowActionsDirective: the directive need a member\");\n }\n $ctrl = $el.controller();\n member = $scope.$eval($attrs.tgMembershipsRowActions);\n render(member);\n $el.on(\"click\", \".pending\", function(event) {\n var onError, onSuccess;\n event.preventDefault();\n onSuccess = function() {\n return $confirm.notify(\"success\", \"We've sent the invitationi again to '\" + $scope.member.email + \"'.\");\n };\n onError = function() {\n return $confirm.notify(\"error\", \"We haven't sent the invitation.\");\n };\n return $rs.memberships.resendInvitation($scope.member.id).then(onSuccess, onError);\n });\n $el.on(\"click\", \".delete\", function(event) {\n var message, title;\n event.preventDefault();\n title = \"Delete member\";\n message = member.user ? member.full_name : \"the invitation to \" + member.email;\n return $confirm.askOnDelete(title, message).then(function(finish) {\n var onError, onSuccess;\n onSuccess = function() {\n finish();\n $ctrl.loadMembers();\n return $confirm.notify(\"success\", null, \"We've deleted \" + message + \".\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\", null, \"We have not been able to delete \" + message + \".\");\n };\n return $repo.remove(member).then(onSuccess, onError);\n });\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgMembershipsRowActions\", [\"$log\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", MembershipsRowActionsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/nav.coffee\n */\n\n(function() {\n var AdminNavigationDirective, module;\n\n AdminNavigationDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var section;\n section = $attrs.tgAdminNavigation;\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\"#adminmenu-\" + section + \" a\").addClass(\"active\");\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaAdmin\");\n\n module.directive(\"tgAdminNavigation\", AdminNavigationDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/project-profile.coffee\n */\n\n(function() {\n var ProjectDefaultValuesDirective, ProjectExportDirective, ProjectModulesDirective, ProjectProfileController, ProjectProfileDirective, bindOnce, debounce, groupBy, joinStr, mixOf, module, taiga, toString, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAdmin\");\n\n ProjectProfileController = (function(_super) {\n __extends(ProjectProfileController, _super);\n\n ProjectProfileController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function ProjectProfileController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Project profile - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:loaded\", (function(_this) {\n return function() {\n return _this.appTitle.set(\"Project profile - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n }\n\n ProjectProfileController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.pointsList = _.sortBy(project.points, \"order\");\n _this.scope.usStatusList = _.sortBy(project.us_statuses, \"order\");\n _this.scope.taskStatusList = _.sortBy(project.task_statuses, \"order\");\n _this.scope.prioritiesList = _.sortBy(project.priorities, \"order\");\n _this.scope.severitiesList = _.sortBy(project.severities, \"order\");\n _this.scope.issueTypesList = _.sortBy(project.issue_types, \"order\");\n _this.scope.issueStatusList = _.sortBy(project.issue_statuses, \"order\");\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ProjectProfileController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n ProjectProfileController.prototype.openDeleteLightbox = function() {\n return this.rootscope.$broadcast(\"deletelightbox:new\", this.scope.project);\n };\n\n return ProjectProfileController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"ProjectProfileController\", ProjectProfileController);\n\n ProjectProfileDirective = function($repo, $confirm, $loading, $navurls, $location) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.save($scope.project);\n promise.then(function() {\n var newUrl;\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n newUrl = $navurls.resolve(\"project-admin-project-profile-details\", {\n project: $scope.project.slug\n });\n $location.path(newUrl);\n return $scope.$emit(\"project:loaded\", $scope.project);\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectProfile\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", \"$tgNavUrls\", \"$tgLocation\", ProjectProfileDirective]);\n\n ProjectDefaultValuesDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.save($scope.project);\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectDefaultValues\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", ProjectDefaultValuesDirective]);\n\n ProjectModulesDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit;\n form = $el.find(\"form\").checksley();\n submit = (function(_this) {\n return function() {\n var promise, target;\n if (!form.validate()) {\n return;\n }\n target = angular.element(\".admin-functionalities a.button-green\");\n $loading.start(target);\n promise = $repo.save($scope.project);\n promise.then(function() {\n $loading.finish(target);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:loaded\", $scope.project);\n });\n return promise.then(null, function(data) {\n $loading.finish(target);\n return $confirm.notify(\"error\", data._error_message);\n });\n };\n })(this);\n $el.on(\"submit\", \"form\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \".admin-functionalities a.button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n $scope.$watch(\"isVideoconferenceActivated\", function(isVideoconferenceActivated) {\n if (isVideoconferenceActivated) {\n return $el.find(\".videoconference-attributes\").removeClass(\"hidden\");\n } else {\n $el.find(\".videoconference-attributes\").addClass(\"hidden\");\n $scope.project.videoconferences = null;\n return $scope.project.videoconferences_salt = \"\";\n }\n });\n return $scope.$watch(\"project\", function(project) {\n if (project.videoconferences != null) {\n return $scope.isVideoconferenceActivated = true;\n } else {\n return $scope.isVideoconferenceActivated = false;\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectModules\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", ProjectModulesDirective]);\n\n ProjectExportDirective = function($window, $rs, $confirm) {\n var link;\n link = function($scope, $el, $attrs) {\n var buttonsEl, hideButtons, hideResult, hideSpinner, resultEl, resultMessageEl, resultTitleEl, setAsyncMessage, setAsyncTitle, setLoadingMessage, setLoadingTitle, setSyncMessage, setSyncTitle, showButtons, showErrorMode, showExportResultAsyncMode, showExportResultSyncMode, showLoadingMode, showResult, showSpinner, spinnerEl;\n buttonsEl = $el.find(\".admin-project-export-buttons\");\n showButtons = function() {\n return buttonsEl.removeClass(\"hidden\");\n };\n hideButtons = function() {\n return buttonsEl.addClass(\"hidden\");\n };\n resultEl = $el.find(\".admin-project-export-result\");\n showResult = function() {\n return resultEl.removeClass(\"hidden\");\n };\n hideResult = function() {\n return resultEl.addClass(\"hidden\");\n };\n spinnerEl = $el.find(\".spin\");\n showSpinner = function() {\n return spinnerEl.removeClass(\"hidden\");\n };\n hideSpinner = function() {\n return spinnerEl.addClass(\"hidden\");\n };\n resultTitleEl = $el.find(\".result-title\");\n setLoadingTitle = function() {\n return resultTitleEl.html(\"We are generating your dump file\");\n };\n setAsyncTitle = function() {\n return resultTitleEl.html(\"We are generating your dump file\");\n };\n setSyncTitle = function() {\n return resultTitleEl.html(\"Your dump file ir ready!\");\n };\n resultMessageEl = $el.find(\".result-message \");\n setLoadingMessage = function() {\n return resultMessageEl.html(\"Please don't close this page.\");\n };\n setAsyncMessage = function() {\n return resultMessageEl.html(\"We will send you an email when ready.\");\n };\n setSyncMessage = function(url) {\n return resultMessageEl.html(\"If the download doesn't start automatically click here.\");\n };\n showLoadingMode = function() {\n showSpinner();\n setLoadingTitle();\n setLoadingMessage();\n hideButtons();\n return showResult();\n };\n showExportResultAsyncMode = function() {\n hideSpinner();\n setAsyncTitle();\n return setAsyncMessage();\n };\n showExportResultSyncMode = function(url) {\n hideSpinner();\n setSyncTitle();\n return setSyncMessage(url);\n };\n showErrorMode = function() {\n hideSpinner();\n hideResult();\n return showButtons();\n };\n return $el.on(\"click\", \"a.button-export\", debounce(2000, (function(_this) {\n return function(event) {\n var onError, onSuccess;\n event.preventDefault();\n onSuccess = function(result) {\n var dumpUrl;\n if (result.status === 202) {\n return showExportResultAsyncMode();\n } else {\n dumpUrl = result.data.url;\n showExportResultSyncMode(dumpUrl);\n return $window.open(dumpUrl, \"_blank\");\n }\n };\n onError = function(result) {\n var errorMsg, _ref;\n showErrorMode();\n errorMsg = \"Our oompa loompas have some problems generasting your dump. Please try again. \";\n if (result.status === 429) {\n errorMsg = \"Sorry, our oompa loompas are very busy right now. Please try again in a few minutes. \";\n } else if ((_ref = result.data) != null ? _ref._error_message : void 0) {\n errorMsg = \"Our oompa loompas have some problems generasting your dump: \" + result.data._error_message;\n }\n return $confirm.notify(\"error\", errorMsg);\n };\n showLoadingMode();\n return $rs.projects[\"export\"]($scope.projectId).then(onSuccess, onError);\n };\n })(this)));\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectExport\", [\"$window\", \"$tgResources\", \"$tgConfirm\", ProjectExportDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/project-profile.coffee\n */\n\n(function() {\n var ColorSelectionDirective, ProjectValuesController, ProjectValuesDirective, bindOnce, debounce, groupBy, joinStr, mixOf, module, taiga, toString, trim,\n __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n trim = this.taiga.trim;\n\n toString = this.taiga.toString;\n\n joinStr = this.taiga.joinStr;\n\n groupBy = this.taiga.groupBy;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaAdmin\");\n\n ProjectValuesController = (function(_super) {\n __extends(ProjectValuesController, _super);\n\n ProjectValuesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function ProjectValuesController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n this.moveValue = __bind(this.moveValue, this);\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Project values - \" + _this.scope.sectionName + \" - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"admin:project-values:move\", this.moveValue);\n }\n\n ProjectValuesController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ProjectValuesController.prototype.loadValues = function() {\n return this.rs[this.scope.resource].listValues(this.scope.projectId, this.scope.type).then((function(_this) {\n return function(values) {\n _this.scope.values = values;\n _this.scope.maxValueOrder = _.max(values, \"order\").order;\n return values;\n };\n })(this));\n };\n\n ProjectValuesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.q.all([_this.loadProject(), _this.loadValues()]);\n };\n })(this));\n };\n\n ProjectValuesController.prototype.moveValue = function(ctx, itemValue, itemIndex) {\n var r, values;\n values = this.scope.values;\n r = values.indexOf(itemValue);\n values.splice(r, 1);\n values.splice(itemIndex, 0, itemValue);\n _.each(values, function(value, index) {\n return value.order = index;\n });\n return this.repo.saveAll(values);\n };\n\n return ProjectValuesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"ProjectValuesController\", ProjectValuesController);\n\n ProjectValuesDirective = function($log, $repo, $confirm, $location, animationFrame) {\n var link, linkDragAndDrop, linkValue;\n linkDragAndDrop = function($scope, $el, $attrs) {\n var itemEl, newParentScope, oldParentScope, tdom;\n oldParentScope = null;\n newParentScope = null;\n itemEl = null;\n tdom = $el.find(\".sortable\");\n tdom.sortable({\n handle: \".row.table-main.visualization\",\n dropOnEmpty: true,\n connectWith: \".project-values-body\",\n revert: 400,\n axis: \"y\"\n });\n tdom.on(\"sortstop\", function(event, ui) {\n var itemIndex, itemValue;\n itemEl = ui.item;\n itemValue = itemEl.scope().value;\n itemIndex = itemEl.index();\n return $scope.$broadcast(\"admin:project-values:move\", itemValue, itemIndex);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n linkValue = function($scope, $el, $attrs) {\n var $ctrl, cancel, goToBottomList, initializeNewValue, saveValue, submit, valueType;\n $ctrl = $el.controller();\n valueType = $attrs.type;\n initializeNewValue = function() {\n return $scope.newValue = {\n \"name\": \"\",\n \"is_closed\": false,\n \"is_archived\": false\n };\n };\n initializeNewValue();\n goToBottomList = (function(_this) {\n return function(focus) {\n var table;\n if (focus == null) {\n focus = false;\n }\n table = $el.find(\".table-main\");\n $(document.body).scrollTop(table.offset().top + table.height());\n if (focus) {\n return $(\".new-value input\").focus();\n }\n };\n })(this);\n submit = debounce(2000, (function(_this) {\n return function() {\n var promise;\n promise = $repo.save($scope.project);\n promise.then(function() {\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n return $confirm.notify(\"error\", data._error_message);\n });\n };\n })(this));\n saveValue = debounce(2000, function(target) {\n var form, promise, value;\n form = target.parents(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n value = target.scope().value;\n promise = $repo.save(value);\n promise.then((function(_this) {\n return function() {\n var row;\n row = target.parents(\".row.table-main\");\n row.addClass(\"hidden\");\n return row.siblings(\".visualization\").removeClass('hidden');\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n });\n cancel = function(target) {\n var row, value;\n row = target.parents(\".row.table-main\");\n value = target.scope().value;\n return $scope.$apply(function() {\n row.addClass(\"hidden\");\n value.revert();\n return row.siblings(\".visualization\").removeClass('hidden');\n });\n };\n $el.on(\"submit\", \"form\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \"form a.button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n $el.on(\"click\", \".show-add-new\", function(event) {\n event.preventDefault();\n $el.find(\".new-value\").removeClass('hidden');\n return goToBottomList(true);\n });\n $el.on(\"click\", \".add-new\", debounce(2000, function(event) {\n var form, promise;\n event.preventDefault();\n form = $el.find(\".new-value\").parents(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n $scope.newValue.project = $scope.project.id;\n $scope.newValue.order = $scope.maxValueOrder ? $scope.maxValueOrder + 1 : 1;\n promise = $repo.create(valueType, $scope.newValue);\n promise.then((function(_this) {\n return function() {\n $ctrl.loadValues().then(function() {\n return animationFrame.add(function() {\n return goToBottomList();\n });\n });\n $el.find(\".new-value\").addClass(\"hidden\");\n return initializeNewValue();\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n }));\n $el.on(\"click\", \".delete-new\", function(event) {\n event.preventDefault();\n $el.find(\".new-value\").hide();\n return initializeNewValue();\n });\n $el.on(\"click\", \".edit-value\", function(event) {\n var editionRow, row, target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n row = target.parents(\".row.table-main\");\n row.addClass(\"hidden\");\n editionRow = row.siblings(\".edition\");\n editionRow.removeClass('hidden');\n return editionRow.find('input:visible').first().focus().select();\n });\n $el.on(\"keyup\", \".edition input\", function(event) {\n var target;\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n return saveValue(target);\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n return cancel(target);\n }\n });\n $el.on(\"click\", \".save\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return saveValue(target);\n });\n $el.on(\"click\", \".cancel\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return cancel(target);\n });\n return $el.on(\"click\", \".delete-value\", function(event) {\n var choices, replacement, subtitle, target, title, value;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n value = target.scope().value;\n choices = {};\n _.each($scope.values, function(option) {\n if (value.id !== option.id) {\n return choices[option.id] = option.name;\n }\n });\n title = \"Delete value\";\n subtitle = value.name;\n replacement = \"All items with this value will be changed to\";\n if (_.keys(choices).length === 0) {\n return $confirm.error(\"You can't delete all values.\");\n }\n return $confirm.askChoice(title, subtitle, choices, replacement).then(function(response) {\n var onError, onSucces;\n onSucces = function() {\n return $ctrl.loadValues()[\"finally\"](function() {\n return response.finish();\n });\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n return $repo.remove(value, {\n \"moveTo\": response.selected\n }).then(onSucces, onError);\n });\n });\n };\n link = function($scope, $el, $attrs) {\n linkDragAndDrop($scope, $el, $attrs);\n linkValue($scope, $el, $attrs);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectValues\", [\"$log\", \"$tgRepo\", \"$tgConfirm\", \"$tgLocation\", \"animationFrame\", ProjectValuesDirective]);\n\n ColorSelectionDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $model) {\n var $ctrl;\n $ctrl = $el.controller();\n $scope.$watch($attrs.ngModel, function(element) {\n return $scope.color = element.color;\n });\n $el.on(\"click\", \".current-color\", function(event) {\n var body, target;\n event.preventDefault();\n event.stopPropagation();\n target = angular.element(event.currentTarget);\n $el.find(\".select-color\").hide();\n target.siblings(\".select-color\").show();\n body = angular.element(\"body\");\n return body.on(\"click\", (function(_this) {\n return function(event) {\n if (angular.element(event.target).parent(\".select-color\").length === 0) {\n $el.find(\".select-color\").hide();\n return body.unbind(\"click\");\n }\n };\n })(this));\n });\n $el.on(\"click\", \".select-color .color\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n $scope.$apply(function() {\n return $model.$modelValue.color = target.data(\"color\");\n });\n return $el.find(\".select-color\").hide();\n });\n $el.on(\"click\", \".select-color .selected-color\", function(event) {\n event.preventDefault();\n $scope.$apply(function() {\n return $model.$modelValue.color = $scope.color;\n });\n return $el.find(\".select-color\").hide();\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgColorSelection\", ColorSelectionDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/memberships.coffee\n */\n\n(function() {\n var EditRoleDirective, NewRoleDirective, RolePermissionsDirective, RolesController, RolesDirective, bindMethods, bindOnce, debounce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n bindMethods = this.taiga.bindMethods;\n\n module = angular.module(\"taigaAdmin\");\n\n RolesController = (function(_super) {\n __extends(RolesController, _super);\n\n RolesController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$appTitle\"];\n\n function RolesController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, appTitle) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Permissions\";\n this.scope.project = {};\n this.scope.anyComputableRole = true;\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Roles - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n RolesController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.anyComputableRole = _.some(_.map(project.roles, function(point) {\n return point.computable;\n }));\n return project;\n };\n })(this));\n };\n\n RolesController.prototype.loadRoles = function() {\n return this.rs.roles.list(this.scope.projectId).then((function(_this) {\n return function(data) {\n _this.scope.roles = data;\n _this.scope.role = _this.scope.roles[0];\n return data;\n };\n })(this));\n };\n\n RolesController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadUsersAndRoles();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadRoles();\n };\n })(this));\n };\n\n RolesController.prototype.setRole = function(role) {\n this.scope.role = role;\n return this.scope.$broadcast(\"role:changed\", this.scope.role);\n };\n\n RolesController.prototype[\"delete\"] = function() {\n var choices, replacement, role, subtitle, title, warning, _i, _len, _ref;\n title = \"Delete Role\";\n subtitle = this.scope.role.name;\n replacement = \"All the users with this role will be moved to\";\n warning = \"Be careful, all role estimations will be removed\";\n choices = {};\n _ref = this.scope.roles;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n role = _ref[_i];\n if (role.id !== this.scope.role.id) {\n choices[role.id] = role.name;\n }\n }\n if (_.keys(choices).length === 0) {\n return this.confirm.error(\"You can't delete all values.\");\n }\n return this.confirm.askChoice(title, subtitle, choices, replacement, warning).then((function(_this) {\n return function(response) {\n var promise;\n promise = _this.repo.remove(_this.scope.role, {\n moveTo: response.selected\n });\n promise.then(function() {\n _this.loadProject();\n return _this.loadRoles()[\"finally\"](function() {\n return response.finish();\n });\n });\n return promise.then(null, function() {\n return _this.confirm.notify('error');\n });\n };\n })(this));\n };\n\n RolesController.prototype.setComputable = debounce(2000, function() {\n var onError, onSuccess;\n onSuccess = (function(_this) {\n return function() {\n _this.confirm.notify(\"success\");\n return _this.loadProject();\n };\n })(this);\n onError = (function(_this) {\n return function() {\n _this.confirm.notify(\"error\");\n return _this.scope.role.revert();\n };\n })(this);\n return this.repo.save(this.scope.role).then(onSuccess, onError);\n });\n\n return RolesController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"RolesController\", RolesController);\n\n EditRoleDirective = function($repo, $confirm) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit, toggleView;\n toggleView = function() {\n $el.find('.total').toggle();\n return $el.find('.edit-role').toggle();\n };\n submit = function() {\n var promise;\n $scope.role.name = $el.find(\"input\").val();\n promise = $repo.save($scope.role);\n promise.then(function() {\n return $confirm.notify(\"success\");\n });\n promise.then(null, function(data) {\n return $confirm.notify(\"error\");\n });\n return toggleView();\n };\n $el.on(\"click\", \"a.icon-edit\", function() {\n toggleView();\n $el.find(\"input\").focus();\n return $el.find(\"input\").val($scope.role.name);\n });\n $el.on(\"click\", \"a.save\", submit);\n $el.on(\"keyup\", \"input\", function(event) {\n if (event.keyCode === 13) {\n return submit();\n } else if (event.keyCode === 27) {\n return toggleView();\n }\n });\n $scope.$on(\"role:changed\", function() {\n if ($el.find('.edit-role').is(\":visible\")) {\n return toggleView();\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgEditRole\", [\"$tgRepo\", \"$tgConfirm\", EditRoleDirective]);\n\n RolesDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRoles\", RolesDirective);\n\n NewRoleDirective = function($tgrepo, $confirm) {\n var DEFAULT_PERMISSIONS, link;\n DEFAULT_PERMISSIONS = [\"view_project\", \"view_milestones\", \"view_us\", \"view_tasks\", \"view_issues\"];\n link = function($scope, $el, $attrs) {\n var $ctrl;\n $ctrl = $el.controller();\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $el.on(\"click\", \"a.add-button\", function(event) {\n event.preventDefault();\n $el.find(\".new\").removeClass(\"hidden\");\n $el.find(\".new\").focus();\n return $el.find(\".add-button\").hide();\n });\n return $el.on(\"keyup\", \".new\", function(event) {\n var newRole, onError, onSuccess, target;\n event.preventDefault();\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n newRole = {\n project: $scope.projectId,\n name: target.val(),\n permissions: DEFAULT_PERMISSIONS,\n order: _.max($scope.roles, function(r) {\n return r.order;\n }).order + 1,\n computable: false\n };\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new\").val('');\n onSuccess = function(role) {\n $scope.roles.push(role);\n $ctrl.setRole(role);\n $el.find(\".add-button\").show();\n return $ctrl.loadProject();\n };\n onError = function() {\n return $confirm.notify(\"error\");\n };\n return $tgrepo.create(\"roles\", newRole).then(onSuccess, onError);\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n $el.find(\".new\").addClass(\"hidden\");\n $el.find(\".new\").val('');\n return $el.find(\".add-button\").show();\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgNewRole\", [\"$tgRepo\", \"$tgConfirm\", NewRoleDirective]);\n\n RolePermissionsDirective = function($rootscope, $repo, $confirm) {\n var baseTemplate, categoryTemplate, link, resumeTemplate;\n resumeTemplate = _.template(\"
    <%- category.name %>
    \\n
    \\n
    <%- category.activePermissions %>/<%- category.permissions.length %>
    \\n <% _.each(category.permissions, function(permission) { %>\\n
    active<% } %>\\\"\\n title=\\\"<%- permission.description %>\\\">
    \\n <% }) %>\\n
    \\n
    \");\n categoryTemplate = _.template(\"
    \\\">\\n
    \\n
    \\n
    \\n
    \\n <% _.each(category.permissions, function(permission) { %>\\n
    \\\">\\n <%- permission.description %>\\n
    \\n checked=\\\"checked\\\"<% } %>/>\\n
    \\n Yes\\n No\\n
    \\n
    \\n <% }) %>\\n
    \\n
    \\n
    \");\n baseTemplate = _.template(\"
    \");\n link = function($scope, $el, $attrs) {\n var $ctrl, generateCategoriesFromRole, renderCategory, renderPermissions, renderResume;\n $ctrl = $el.controller();\n generateCategoriesFromRole = function(role) {\n var categories, issuePermissions, milestonePermissions, setActivePermissions, setActivePermissionsPerCategory, taskPermissions, userStoryPermissions, wikiPermissions;\n setActivePermissions = function(permissions) {\n return _.map(permissions, function(x) {\n var _ref;\n return _.extend({}, x, {\n active: (_ref = x[\"key\"], __indexOf.call(role.permissions, _ref) >= 0)\n });\n });\n };\n setActivePermissionsPerCategory = function(category) {\n return _.map(category, function(x) {\n return _.extend({}, x, {\n activePermissions: _.filter(x[\"permissions\"], \"active\").length\n });\n });\n };\n categories = [];\n milestonePermissions = [\n {\n key: \"view_milestones\",\n description: \"View sprints\"\n }, {\n key: \"add_milestone\",\n description: \"Add sprint\"\n }, {\n key: \"modify_milestone\",\n description: \"Modify sprint\"\n }, {\n key: \"delete_milestone\",\n description: \"Delete sprint\"\n }\n ];\n categories.push({\n name: \"Sprints\",\n permissions: setActivePermissions(milestonePermissions)\n });\n userStoryPermissions = [\n {\n key: \"view_us\",\n description: \"View user story\"\n }, {\n key: \"add_us\",\n description: \"Add user story\"\n }, {\n key: \"modify_us\",\n description: \"Modify user story\"\n }, {\n key: \"delete_us\",\n description: \"Delete user story\"\n }\n ];\n categories.push({\n name: \"User Stories\",\n permissions: setActivePermissions(userStoryPermissions)\n });\n taskPermissions = [\n {\n key: \"view_tasks\",\n description: \"View tasks\"\n }, {\n key: \"add_task\",\n description: \"Add task\"\n }, {\n key: \"modify_task\",\n description: \"Modify task\"\n }, {\n key: \"delete_task\",\n description: \"Delete task\"\n }\n ];\n categories.push({\n name: \"Tasks\",\n permissions: setActivePermissions(taskPermissions)\n });\n issuePermissions = [\n {\n key: \"view_issues\",\n description: \"View issues\"\n }, {\n key: \"add_issue\",\n description: \"Add issue\"\n }, {\n key: \"modify_issue\",\n description: \"Modify issue\"\n }, {\n key: \"delete_issue\",\n description: \"Delete issue\"\n }\n ];\n categories.push({\n name: \"Issues\",\n permissions: setActivePermissions(issuePermissions)\n });\n wikiPermissions = [\n {\n key: \"view_wiki_pages\",\n description: \"View wiki pages\"\n }, {\n key: \"add_wiki_page\",\n description: \"Add wiki page\"\n }, {\n key: \"modify_wiki_page\",\n description: \"Modify wiki page\"\n }, {\n key: \"delete_wiki_page\",\n description: \"Delete wiki page\"\n }, {\n key: \"view_wiki_links\",\n description: \"View wiki links\"\n }, {\n key: \"add_wiki_link\",\n description: \"Add wiki link\"\n }, {\n key: \"delete_wiki_link\",\n description: \"Delete wiki link\"\n }\n ];\n categories.push({\n name: \"Wiki\",\n permissions: setActivePermissions(wikiPermissions)\n });\n return setActivePermissionsPerCategory(categories);\n };\n renderResume = function(element, category) {\n return element.find(\".resume\").html(resumeTemplate({\n category: category\n }));\n };\n renderCategory = function(category, index) {\n var html;\n html = categoryTemplate({\n category: category,\n index: index\n });\n html = angular.element(html);\n renderResume(html, category);\n return html;\n };\n renderPermissions = function() {\n var html;\n $el.off();\n html = baseTemplate();\n _.each(generateCategoriesFromRole($scope.role), function(category, index) {\n return html = angular.element(html).append(renderCategory(category, index));\n });\n $el.html(html);\n $el.on(\"click\", \".resume\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return target.next().toggleClass(\"open\");\n });\n return $el.on(\"change\", \".category-item input\", function(event) {\n var getActivePermissions, onError, onSuccess, target;\n getActivePermissions = function() {\n var activePermissions;\n activePermissions = _.filter($el.find(\".category-item input\"), function(t) {\n return angular.element(t).is(\":checked\");\n });\n activePermissions = _.sortBy(_.map(activePermissions, function(t) {\n var permission;\n return permission = angular.element(t).parents(\".category-item\").data(\"id\");\n }));\n activePermissions.push(\"view_project\");\n return activePermissions;\n };\n target = angular.element(event.currentTarget);\n $scope.role.permissions = getActivePermissions();\n onSuccess = function(role) {\n var categories, categoryId;\n categories = generateCategoriesFromRole(role);\n categoryId = target.parents(\".category-config\").data(\"id\");\n renderResume(target.parents(\".category-config\"), categories[categoryId]);\n $rootscope.$broadcast(\"projects:reload\");\n $confirm.notify(\"success\");\n return $ctrl.loadProject();\n };\n onError = function() {\n $confirm.notify(\"error\");\n target.prop(\"checked\", !target.prop(\"checked\"));\n return $scope.role.permissions = getActivePermissions();\n };\n return $repo.save($scope.role).then(onSuccess, onError);\n });\n };\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n $scope.$on(\"role:changed\", function() {\n return renderPermissions();\n });\n return bindOnce($scope, $attrs.ngModel, renderPermissions);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgRolePermissions\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", RolePermissionsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/admin/third-parties.coffee\n */\n\n(function() {\n var BitbucketController, BitbucketWebhooksDirective, GithubController, GithubWebhooksDirective, GitlabController, GitlabWebhooksDirective, NewWebhookDirective, SelectInputText, ValidOriginIpsDirective, WebhookDirective, WebhooksController, bindMethods, debounce, mixOf, module, taiga, timeout,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindMethods = this.taiga.bindMethods;\n\n debounce = this.taiga.debounce;\n\n timeout = this.taiga.timeout;\n\n module = angular.module(\"taigaAdmin\");\n\n WebhooksController = (function(_super) {\n __extends(WebhooksController, _super);\n\n WebhooksController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function WebhooksController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Webhooks\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Webhooks - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"webhooks:reload\", this.loadWebhooks);\n }\n\n WebhooksController.prototype.loadWebhooks = function() {\n return this.rs.webhooks.list(this.scope.projectId).then((function(_this) {\n return function(webhooks) {\n return _this.scope.webhooks = webhooks;\n };\n })(this));\n };\n\n WebhooksController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n WebhooksController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadWebhooks();\n };\n })(this));\n };\n\n return WebhooksController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"WebhooksController\", WebhooksController);\n\n WebhookDirective = function($rs, $repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var cancel, openHistory, save, showEditMode, showVisualizationMode, updateLogs, updateShowHideHistoryText, webhook;\n webhook = $scope.$eval($attrs.tgWebhook);\n updateLogs = function() {\n return $rs.webhooklogs.list(webhook.id).then((function(_this) {\n return function(webhooklogs) {\n var log, _i, _len, _ref;\n for (_i = 0, _len = webhooklogs.length; _i < _len; _i++) {\n log = webhooklogs[_i];\n log.validStatus = (200 <= (_ref = log.status) && _ref < 300);\n log.prettySentHeaders = _.map(_.pairs(log.request_headers), function(_arg) {\n var header, value;\n header = _arg[0], value = _arg[1];\n return \"\" + header + \": \" + value;\n }).join(\"\\n\");\n log.prettySentData = JSON.stringify(log.request_data.data, void 0, 2);\n log.prettyDate = moment(log.created).format(\"DD MMM YYYY [at] hh:mm:ss\");\n }\n webhook.logs_counter = webhooklogs.length;\n webhook.logs = webhooklogs;\n return updateShowHideHistoryText();\n };\n })(this));\n };\n updateShowHideHistoryText = function() {\n var historyElement, textElement;\n textElement = $el.find(\".toggle-history\");\n historyElement = textElement.parents(\".single-webhook-wrapper\").find(\".webhooks-history\");\n if (historyElement.hasClass(\"open\")) {\n return textElement.text(\"(Hide history)\");\n } else {\n return textElement.text(\"(Show history)\");\n }\n };\n showVisualizationMode = function() {\n $el.find(\".edition-mode\").addClass(\"hidden\");\n return $el.find(\".visualization-mode\").removeClass(\"hidden\");\n };\n showEditMode = function() {\n $el.find(\".visualization-mode\").addClass(\"hidden\");\n return $el.find(\".edition-mode\").removeClass(\"hidden\");\n };\n openHistory = function() {\n return $el.find(\".webhooks-history\").addClass(\"open\");\n };\n cancel = function() {\n showVisualizationMode();\n return $scope.$apply(function() {\n return webhook.revert();\n });\n };\n save = debounce(2000, function(target) {\n var form, promise, value;\n form = target.parents(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n value = target.scope().value;\n promise = $repo.save(webhook);\n promise.then((function(_this) {\n return function() {\n return showVisualizationMode();\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n });\n $el.on(\"click\", \".test-webhook\", function() {\n openHistory();\n return $rs.webhooks.test(webhook.id).then((function(_this) {\n return function() {\n return updateLogs();\n };\n })(this));\n });\n $el.on(\"click\", \".edit-webhook\", function() {\n return showEditMode();\n });\n $el.on(\"click\", \".cancel-existing\", function() {\n return cancel();\n });\n $el.on(\"click\", \".edit-existing\", function(event) {\n var target;\n event.preventDefault();\n target = angular.element(event.currentTarget);\n return save(target);\n });\n $el.on(\"keyup\", \".edition-mode input\", function(event) {\n var target;\n if (event.keyCode === 13) {\n target = angular.element(event.currentTarget);\n return saveWebhook(target);\n } else if (event.keyCode === 27) {\n target = angular.element(event.currentTarget);\n return cancel(target);\n }\n });\n $el.on(\"click\", \".delete-webhook\", function() {\n var message, title;\n title = \"Delete webhook\";\n message = \"Webhook '\" + webhook.name + \"'\";\n return $confirm.askOnDelete(title, message).then((function(_this) {\n return function(finish) {\n var onError, onSucces;\n onSucces = function() {\n finish();\n return $scope.$emit(\"webhooks:reload\");\n };\n onError = function() {\n finish(false);\n return $confirm.notify(\"error\");\n };\n return $repo.remove(webhook).then(onSucces, onError);\n };\n })(this));\n });\n $el.on(\"click\", \".toggle-history\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n if ((webhook.logs == null) || webhook.logs.length === 0) {\n return updateLogs().then(function() {\n return timeout(0, function() {\n $el.find(\".webhooks-history\").toggleClass(\"open\");\n return updateShowHideHistoryText();\n });\n });\n } else {\n $el.find(\".webhooks-history\").toggleClass(\"open\");\n return $scope.$apply(function() {\n return updateShowHideHistoryText();\n });\n }\n });\n $el.on(\"click\", \".history-single\", function(event) {\n var target;\n target = angular.element(event.currentTarget);\n target.toggleClass(\"history-single-open\");\n return target.siblings(\".history-single-response\").toggleClass(\"open\");\n });\n return $el.on(\"click\", \".resend-request\", function(event) {\n var log, target;\n target = angular.element(event.currentTarget);\n log = target.data(\"log\");\n return $rs.webhooklogs.resend(log).then((function(_this) {\n return function() {\n return updateLogs();\n };\n })(this));\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgWebhook\", [\"$tgResources\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", WebhookDirective]);\n\n NewWebhookDirective = function($rs, $repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var addWebhookDOMNode, formDOMNode, initializeNewValue, webhook;\n webhook = $scope.$eval($attrs.tgWebhook);\n formDOMNode = $el.find(\".new-webhook-form\");\n addWebhookDOMNode = $el.find(\".add-webhook\");\n initializeNewValue = function() {\n return $scope.newValue = {\n \"name\": \"\",\n \"url\": \"\",\n \"key\": \"\"\n };\n };\n initializeNewValue();\n $scope.$watch(\"webhooks\", function(webhooks) {\n if (webhooks != null) {\n if (webhooks.length === 0) {\n formDOMNode.removeClass(\"hidden\");\n addWebhookDOMNode.addClass(\"hidden\");\n return formDOMNode.find(\"input\")[0].focus();\n } else {\n formDOMNode.addClass(\"hidden\");\n return addWebhookDOMNode.removeClass(\"hidden\");\n }\n }\n });\n formDOMNode.on(\"click\", \".add-new\", debounce(2000, function(event) {\n var form, promise;\n event.preventDefault();\n form = formDOMNode.checksley();\n if (!form.validate()) {\n return;\n }\n $scope.newValue.project = $scope.project.id;\n promise = $repo.create(\"webhooks\", $scope.newValue);\n promise.then((function(_this) {\n return function() {\n $scope.$emit(\"webhooks:reload\");\n return initializeNewValue();\n };\n })(this));\n return promise.then(null, function(data) {\n $confirm.notify(\"error\");\n return form.setErrors(data);\n });\n }));\n formDOMNode.on(\"click\", \".cancel-new\", function(event) {\n return $scope.$apply(function() {\n return initializeNewValue();\n });\n });\n return addWebhookDOMNode.on(\"click\", function(event) {\n formDOMNode.removeClass(\"hidden\");\n return formDOMNode.find(\"input\")[0].focus();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgNewWebhook\", [\"$tgResources\", \"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", NewWebhookDirective]);\n\n GithubController = (function(_super) {\n __extends(GithubController, _super);\n\n GithubController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function GithubController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Github\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Github - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n GithubController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"github\").then((function(_this) {\n return function(github) {\n return _this.scope.github = github;\n };\n })(this));\n };\n\n GithubController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n GithubController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return GithubController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"GithubController\", GithubController);\n\n GitlabController = (function(_super) {\n __extends(GitlabController, _super);\n\n GitlabController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function GitlabController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Gitlab\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Gitlab - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:modules:reload\", (function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n }\n\n GitlabController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"gitlab\").then((function(_this) {\n return function(gitlab) {\n return _this.scope.gitlab = gitlab;\n };\n })(this));\n };\n\n GitlabController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n GitlabController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return GitlabController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"GitlabController\", GitlabController);\n\n BitbucketController = (function(_super) {\n __extends(BitbucketController, _super);\n\n BitbucketController.$inject = [\"$scope\", \"$tgRepo\", \"$tgResources\", \"$routeParams\", \"$appTitle\"];\n\n function BitbucketController(scope, repo, rs, params, appTitle) {\n var promise;\n this.scope = scope;\n this.repo = repo;\n this.rs = rs;\n this.params = params;\n this.appTitle = appTitle;\n bindMethods(this);\n this.scope.sectionName = \"Bitbucket\";\n this.scope.project = {};\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(\"Bitbucket - \" + _this.scope.project.name);\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n this.scope.$on(\"project:modules:reload\", (function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n }\n\n BitbucketController.prototype.loadModules = function() {\n return this.rs.modules.list(this.scope.projectId, \"bitbucket\").then((function(_this) {\n return function(bitbucket) {\n return _this.scope.bitbucket = bitbucket;\n };\n })(this));\n };\n\n BitbucketController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n BitbucketController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadModules();\n };\n })(this));\n };\n\n return BitbucketController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin));\n\n module.controller(\"BitbucketController\", BitbucketController);\n\n SelectInputText = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $el.on(\"click\", \".select-input-content\", function() {\n $el.find(\"input\").select();\n return $el.find(\".help-copy\").addClass(\"visible\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgSelectInputText\", SelectInputText);\n\n GithubWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.github, \"github\");\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGithubWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", GithubWebhooksDirective]);\n\n GitlabWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.gitlab, \"gitlab\");\n promise.then(function() {\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:modules:reload\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgGitlabWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", GitlabWebhooksDirective]);\n\n BitbucketWebhooksDirective = function($repo, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs) {\n var form, submit, submitButton;\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.saveAttribute($scope.bitbucket, \"bitbucket\");\n promise.then(function() {\n $loading.finish(submitButton);\n $confirm.notify(\"success\");\n return $scope.$emit(\"project:modules:reload\");\n });\n return promise.then(null, function(data) {\n $loading.finish(submitButton);\n form.setErrors(data);\n if (data._error_message) {\n return $confirm.notify(\"error\", data._error_message);\n }\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n return $el.on(\"click\", \".submit-button\", submit);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgBitbucketWebhooks\", [\"$tgRepo\", \"$tgConfirm\", \"$tgLoading\", BitbucketWebhooksDirective]);\n\n ValidOriginIpsDirective = function() {\n var link;\n link = function($scope, $el, $attrs, $ngModel) {\n return $ngModel.$parsers.push(function(value) {\n value = $.trim(value);\n if (value === \"\") {\n return [];\n }\n return value.split(\",\");\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n require: \"ngModel\"\n };\n };\n\n module.directive(\"tgValidOriginIps\", ValidOriginIpsDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var CreateProject, DeleteProjectDirective, bindOnce, debounce, module, taiga, timeout;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n timeout = this.taiga.timeout;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaProject\");\n\n CreateProject = function($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory) {\n var link;\n link = function($scope, $el, attrs) {\n var form, onErrorSubmit, onSuccessSubmit, submit, submitButton;\n $scope.data = {};\n $scope.templates = [];\n form = $el.find(\"form\").checksley({\n \"onlyOneErrorElement\": true\n });\n onSuccessSubmit = function(response) {\n $cacheFactory.get('$http').removeAll();\n $loading.finish(submitButton);\n $rootscope.$broadcast(\"projects:reload\");\n $confirm.notify(\"success\", \"Success\");\n $location.url($projectUrl.get(response));\n return lightboxService.close($el);\n };\n onErrorSubmit = function(response) {\n var error_field, error_step, selectors, _i, _len, _ref;\n $loading.finish(submitButton);\n form.setErrors(response);\n selectors = [];\n _ref = _.keys(response);\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n error_field = _ref[_i];\n selectors.push(\"[name=\" + error_field + \"]\");\n }\n $el.find(\".active\").removeClass(\"active\");\n error_step = $el.find(selectors.join(\",\")).first().parents(\".wizard-step\");\n error_step.addClass(\"active\");\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(error_step.data(\"step\"));\n };\n submit = (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if (!form.validate()) {\n return;\n }\n $loading.start(submitButton);\n promise = $repo.create(\"projects\", $scope.data);\n return promise.then(onSuccessSubmit, onErrorSubmit);\n };\n })(this);\n $scope.$on(\"projects:create\", function() {\n $scope.data = {\n total_story_points: 100,\n total_milestones: 5\n };\n if (!$scope.templates.length) {\n $rs.projects.templates().then((function(_this) {\n return function(result) {\n $scope.templates = result;\n return $scope.data.creation_template = _.head(_.filter($scope.templates, function(x) {\n return x.slug === \"scrum\";\n })).id;\n };\n })(this));\n } else {\n $scope.data.creation_template = _.head(_.filter($scope.templates, function(x) {\n return x.slug === \"scrum\";\n })).id;\n }\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\".create-step1\").addClass(\"active\");\n lightboxService.open($el);\n return timeout(600, function() {\n return $el.find(\".progress-bar\").addClass('step1');\n });\n });\n $el.on(\"click\", \".button-next\", function(event) {\n var current, field, next, step, valid, _i, _len, _ref;\n event.preventDefault();\n current = $el.find(\".active\");\n valid = true;\n _ref = form.fields;\n for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n field = _ref[_i];\n if (current.find(\"[name=\" + (field.element.attr('name')) + \"]\").length) {\n valid = field.validate() !== false && valid;\n }\n }\n if (!valid) {\n return;\n }\n next = current.next();\n current.toggleClass('active');\n next.toggleClass('active');\n step = next.data('step');\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step);\n });\n $el.on(\"click\", \".button-prev\", function(event) {\n var current, prev, step;\n event.preventDefault();\n current = $el.find(\".active\");\n prev = current.prev();\n current.toggleClass('active');\n prev.toggleClass('active');\n step = prev.data('step');\n return $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step);\n });\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $el.on(\"click\", \".close\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbCreateProject\", [\"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$location\", \"$tgNavUrls\", \"$tgResources\", \"$projectUrl\", \"$tgLoading\", \"lightboxService\", \"$cacheFactory\", CreateProject]);\n\n DeleteProjectDirective = function($repo, $rootscope, $auth, $location, $navUrls, $confirm, lightboxService, tgLoader) {\n var link;\n link = function($scope, $el, $attrs) {\n var projectToDelete, submit;\n projectToDelete = null;\n $scope.$on(\"deletelightbox:new\", function(ctx, project) {\n lightboxService.open($el);\n return projectToDelete = project;\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = function() {\n var promise;\n tgLoader.start();\n lightboxService.close($el);\n promise = $repo.remove(projectToDelete);\n promise.then(function(data) {\n tgLoader.pageLoaded();\n $rootscope.$broadcast(\"projects:reload\");\n $location.path($navUrls.resolve(\"home\"));\n return $confirm.notify(\"success\");\n });\n return promise.then(null, function() {\n $confirm.notify(\"error\");\n return lightboxService.close($el);\n });\n };\n $el.on(\"click\", \".button-red\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n return $el.on(\"click\", \".button-green\", function(event) {\n event.preventDefault();\n return submit();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgLbDeleteProject\", [\"$tgRepo\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"$tgConfirm\", \"lightboxService\", \"tgLoader\", DeleteProjectDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/common/attachments.coffee\n */\n\n(function() {\n var ProjectController, ProjectsController, ProjectsListDirective, ProjectsPaginationDirective, bindOnce, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaProject\");\n\n bindOnce = this.taiga.bindOnce;\n\n ProjectsController = (function(_super) {\n __extends(ProjectsController, _super);\n\n ProjectsController.$inject = [\"$scope\", \"$q\", \"$tgResources\", \"$rootScope\", \"$tgNavUrls\", \"$tgAuth\", \"$tgLocation\", \"$appTitle\", \"$projectUrl\", \"tgLoader\"];\n\n function ProjectsController(scope, q, rs, rootscope, navUrls, auth, location, appTitle, projectUrl, tgLoader) {\n var promise;\n this.scope = scope;\n this.q = q;\n this.rs = rs;\n this.rootscope = rootscope;\n this.navUrls = navUrls;\n this.auth = auth;\n this.location = location;\n this.appTitle = appTitle;\n this.projectUrl = projectUrl;\n this.appTitle.set(\"Projects\");\n if (!this.auth.isAuthenticated()) {\n this.location.path(this.navUrls.resolve(\"login\"));\n }\n this.user = this.auth.getUser();\n this.projects = [];\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.scope.$emit(\"projects:loaded\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n promise[\"finally\"](tgLoader.pageLoaded);\n }\n\n ProjectsController.prototype.loadInitialData = function() {\n return this.rs.projects.list().then((function(_this) {\n return function(projects) {\n var project, _i, _len;\n _this.projects = {\n 'recents': projects.slice(0, 8),\n 'all': projects\n };\n for (_i = 0, _len = projects.length; _i < _len; _i++) {\n project = projects[_i];\n project.url = _this.projectUrl.get(project);\n }\n return projects;\n };\n })(this));\n };\n\n ProjectsController.prototype.newProject = function() {\n return this.rootscope.$broadcast(\"projects:create\");\n };\n\n ProjectsController.prototype.logout = function() {\n this.auth.logout();\n return this.location.path(this.navUrls.resolve(\"login\"));\n };\n\n return ProjectsController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectsController\", ProjectsController);\n\n ProjectController = (function(_super) {\n __extends(ProjectController, _super);\n\n ProjectController.$inject = [\"$scope\", \"$tgResources\", \"$tgRepo\", \"$routeParams\", \"$q\", \"$rootScope\", \"$appTitle\", \"$tgLocation\", \"$tgNavUrls\"];\n\n function ProjectController(scope, rs, repo, params, q, rootscope, appTitle, location, navUrls) {\n var promise;\n this.scope = scope;\n this.rs = rs;\n this.repo = repo;\n this.params = params;\n this.q = q;\n this.rootscope = rootscope;\n this.appTitle = appTitle;\n this.location = location;\n this.navUrls = navUrls;\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n _this.appTitle.set(_this.scope.project.name);\n return _this.scope.$emit(\"regenerate:project-pagination\");\n };\n })(this));\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n ProjectController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadPageData();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.scope.$emit(\"project:loaded\", _this.scope.project);\n };\n })(this));\n };\n\n ProjectController.prototype.loadPageData = function() {\n return this.q.all([this.loadProjectStats(), this.loadProject()]);\n };\n\n ProjectController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n return project;\n };\n })(this));\n };\n\n ProjectController.prototype.loadProjectStats = function() {\n return this.rs.projects.stats(this.scope.projectId).then((function(_this) {\n return function(stats) {\n _this.scope.stats = stats;\n return stats;\n };\n })(this));\n };\n\n return ProjectController;\n\n })(taiga.Controller);\n\n module.controller(\"ProjectController\", ProjectController);\n\n ProjectsPaginationDirective = function($timeout) {\n var link;\n link = function($scope, $el, $attrs) {\n var checkButtonVisibility, container, containerSize, hasNextPage, hasPagination, hasPrevPage, hide, nextBtn, nextPage, pageSize, prevBtn, prevPage, remove, render, visible;\n prevBtn = $el.find(\".v-pagination-previous\");\n nextBtn = $el.find(\".v-pagination-next\");\n container = $el.find(\"ul\");\n pageSize = 0;\n containerSize = 0;\n render = function() {\n pageSize = $el.find(\".v-pagination-list\").height();\n if (container.find(\"li\").length) {\n if (hasPagination()) {\n if (hasNextPage()) {\n visible(nextBtn);\n } else {\n hide(nextBtn);\n }\n if (hasPrevPage()) {\n return visible(prevBtn);\n } else {\n return hide(prevBtn);\n }\n } else {\n return remove();\n }\n } else {\n return remove();\n }\n };\n hasPagination = function() {\n containerSize = container.height();\n return containerSize > pageSize;\n };\n hasPrevPage = function(top) {\n if (top == null) {\n top = -parseInt(container.css('top'), 10) || 0;\n }\n return top !== 0;\n };\n hasNextPage = function(top) {\n containerSize = container.height();\n if (!top) {\n top = -parseInt(container.css('top'), 10) || 0;\n }\n return containerSize > pageSize && top + pageSize < containerSize;\n };\n nextPage = function(callback) {\n var lastLi, maxTop, newTop, top;\n top = parseInt(container.css('top'), 10);\n newTop = top - pageSize;\n lastLi = $el.find(\".v-pagination-list li:last-child\");\n maxTop = -((lastLi.position().top + lastLi.outerHeight()) - pageSize);\n if (newTop < maxTop) {\n newTop = maxTop;\n }\n container.animate({\n \"top\": newTop\n }, callback);\n return newTop;\n };\n prevPage = function(callback) {\n var newTop, top;\n top = parseInt(container.css('top'), 10);\n newTop = top + pageSize;\n if (newTop > 0) {\n newTop = 0;\n }\n container.animate({\n \"top\": newTop\n }, callback);\n return newTop;\n };\n visible = function(element) {\n return element.css('visibility', 'visible');\n };\n hide = function(element) {\n return element.css('visibility', 'hidden');\n };\n checkButtonVisibility = function() {};\n remove = function() {\n container.css('top', 0);\n hide(prevBtn);\n return hide(nextBtn);\n };\n $el.on(\"click\", \".v-pagination-previous\", function(event) {\n var newTop;\n event.preventDefault();\n if (container.is(':animated')) {\n return;\n }\n visible(nextBtn);\n newTop = prevPage();\n if (!hasPrevPage(newTop)) {\n return hide(prevBtn);\n }\n });\n $el.on(\"click\", \".v-pagination-next\", function(event) {\n var newTop;\n event.preventDefault();\n if (container.is(':animated')) {\n return;\n }\n visible(prevBtn);\n newTop = -nextPage();\n if (!hasNextPage(newTop)) {\n return hide(nextBtn);\n }\n });\n $scope.$on(\"regenerate:project-pagination\", function() {\n remove();\n return render();\n });\n $(window).on(\"resize.projects-pagination\", render);\n return $scope.$on(\"$destroy\", function() {\n return $(window).off(\"resize.projects-pagination\");\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectsPagination\", ['$timeout', ProjectsPaginationDirective]);\n\n ProjectsListDirective = function($compile, $template) {\n var link, template;\n template = $template.get('project/project-list.html', true);\n link = function($scope, $el, $attrs, $ctrls) {\n var render;\n render = function(projects) {\n $el.html($compile(template({\n projects: projects\n }))($scope));\n return $scope.$emit(\"regenerate:project-pagination\");\n };\n return $scope.$watch(\"projects\", function(projects) {\n if (projects != null) {\n return render(projects);\n }\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgProjectsList\", [\"$compile\", \"$tgTemplate\", ProjectsListDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/bind.coffee\n */\n\n(function() {\n var BindHtmlDirective, BindOnceAltDirective, BindOnceBindDirective, BindOnceHrefDirective, BindOnceHtmlDirective, BindOnceRefDirective, BindOnceSrcDirective, BindOnceTitleDirective, BindTitleDirective, bindOnce, module;\n\n bindOnce = this.taiga.bindOnce;\n\n BindOnceBindDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoBind, function(val) {\n return $el.text(val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceHtmlDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoHtml, function(val) {\n return $el.html(val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceRefDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoRef, function(val) {\n return $el.html(\"#\" + val + \" \");\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceSrcDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoSrc, function(val) {\n return $el.attr(\"src\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceHrefDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoHref, function(val) {\n return $el.attr(\"href\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceAltDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoAlt, function(val) {\n return $el.attr(\"alt\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindOnceTitleDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return bindOnce($scope, $attrs.tgBoTitle, function(val) {\n return $el.attr(\"title\", val);\n });\n };\n return {\n link: link\n };\n };\n\n BindTitleDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$watch($attrs.tgTitleHtml, function(val) {\n if (val != null) {\n return $el.attr(\"title\", val);\n }\n });\n };\n return {\n link: link\n };\n };\n\n BindHtmlDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$watch($attrs.tgBindHtml, function(val) {\n if (val != null) {\n return $el.html(val);\n }\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaBase\");\n\n module.directive(\"tgBoBind\", BindOnceBindDirective);\n\n module.directive(\"tgBoHtml\", BindOnceHtmlDirective);\n\n module.directive(\"tgBoRef\", BindOnceRefDirective);\n\n module.directive(\"tgBoSrc\", BindOnceSrcDirective);\n\n module.directive(\"tgBoHref\", BindOnceHrefDirective);\n\n module.directive(\"tgBoAlt\", BindOnceAltDirective);\n\n module.directive(\"tgBoTitle\", BindOnceTitleDirective);\n\n module.directive(\"tgBindTitle\", BindTitleDirective);\n\n module.directive(\"tgBindHtml\", BindHtmlDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/conf.coffee\n */\n\n(function() {\n var ConfigurationService, module;\n\n ConfigurationService = (function() {\n function ConfigurationService() {\n this.config = window.taigaConfig;\n }\n\n ConfigurationService.prototype.get = function(key, defaultValue) {\n if (defaultValue == null) {\n defaultValue = null;\n }\n if (_.has(this.config, key)) {\n return this.config[key];\n }\n return defaultValue;\n };\n\n return ConfigurationService;\n\n })();\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgConfig\", ConfigurationService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/contrib.coffee\n */\n\n(function() {\n var ContribController, module, taigaContribPlugins,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taigaContribPlugins = this.taigaContribPlugins = this.taigaContribPlugins || [];\n\n ContribController = (function(_super) {\n __extends(ContribController, _super);\n\n ContribController.$inject = [\"$rootScope\", \"$scope\", \"$routeParams\", \"$tgRepo\", \"$tgResources\", \"$tgConfirm\", \"$appTitle\"];\n\n function ContribController(rootScope, scope, params, repo, rs, confirm, appTitle) {\n var promise;\n this.rootScope = rootScope;\n this.scope = scope;\n this.params = params;\n this.repo = repo;\n this.rs = rs;\n this.confirm = confirm;\n this.appTitle = appTitle;\n this.scope.currentPlugin = _.first(_.where(taigaContribPlugins, {\n \"slug\": this.params.plugin\n }));\n this.scope.pluginTemplate = \"contrib/\" + this.scope.currentPlugin.slug;\n this.scope.projectSlug = this.params.pslug;\n this.scope.adminPlugins = _.where(this.rootScope.contribPlugins, {\n \"type\": \"admin\"\n });\n promise = this.loadInitialData();\n promise.then((function(_this) {\n return function() {\n return _this.appTitle.set(_this.scope.project.name);\n };\n })(this));\n promise.then(null, (function(_this) {\n return function() {\n return _this.confirm.notify(\"error\");\n };\n })(this));\n }\n\n ContribController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n _this.scope.$broadcast('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n ContribController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n return ContribController;\n\n })(taiga.Controller);\n\n module = angular.module(\"taigaBase\");\n\n module.controller(\"ContribController\", ContribController);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/filters.coffee\n */\n\n(function() {\n var FiltersStorageService, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n FiltersStorageService = (function(_super) {\n __extends(FiltersStorageService, _super);\n\n FiltersStorageService.$inject = [\"$tgStorage\", \"$routeParams\"];\n\n function FiltersStorageService(storage, params) {\n this.storage = storage;\n this.params = params;\n }\n\n FiltersStorageService.prototype.generateHash = function(components) {\n if (components == null) {\n components = [];\n }\n components = _.map(components, function(x) {\n return JSON.stringify(x);\n });\n return hex_sha1(components.join(\":\"));\n };\n\n return FiltersStorageService;\n\n })(taiga.Service);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/http.coffee\n */\n\n(function() {\n var HttpService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n HttpService = (function(_super) {\n __extends(HttpService, _super);\n\n HttpService.$inject = [\"$http\", \"$q\", \"$tgStorage\"];\n\n HttpService.prototype.headers = function() {\n var token;\n token = this.storage.get('token');\n if (token) {\n return {\n \"Authorization\": \"Bearer \" + token\n };\n }\n return {};\n };\n\n function HttpService(http, q, storage) {\n this.http = http;\n this.q = q;\n this.storage = storage;\n HttpService.__super__.constructor.call(this);\n }\n\n HttpService.prototype.request = function(options) {\n options.headers = _.merge({}, options.headers || {}, this.headers());\n if (_.isPlainObject(options.data)) {\n options.data = JSON.stringify(options.data);\n }\n return this.http(options);\n };\n\n HttpService.prototype.get = function(url, params, options) {\n options = _.merge({\n method: \"GET\",\n url: url\n }, options);\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.post = function(url, data, params, options) {\n options = _.merge({\n method: \"POST\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.put = function(url, data, params, options) {\n options = _.merge({\n method: \"PUT\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype.patch = function(url, data, params, options) {\n options = _.merge({\n method: \"PATCH\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n HttpService.prototype[\"delete\"] = function(url, data, params, options) {\n options = _.merge({\n method: \"DELETE\",\n url: url\n }, options);\n if (data) {\n options.data = data;\n }\n if (params) {\n options.params = params;\n }\n return this.request(options);\n };\n\n return HttpService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgHttp\", HttpService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/i18n.coffee\n */\n\n(function() {\n var I18nDirective, I18nService, bindOnce, defaults, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n defaults = {\n ns: \"app\",\n fallbackLng: \"en\",\n async: false,\n lng: \"en\"\n };\n\n I18nService = (function(_super) {\n __extends(I18nService, _super);\n\n function I18nService(rootscope, localesEn) {\n this.rootscope = rootscope;\n this.options = _.clone(defaults, true);\n this.options.resStore = {\n en: {\n app: localesEn\n }\n };\n }\n\n I18nService.prototype.setLanguage = function(language) {\n i18n.setLng(language);\n this.rootscope.currentLang = language;\n return this.rootscope.$broadcast(\"i18n:changeLang\", language);\n };\n\n I18nService.prototype.initialize = function() {\n i18n.init(this.options);\n return this.rootscope.t = i18n.t;\n };\n\n I18nService.prototype.t = function(path, opts) {\n return i18n.t(path, opts);\n };\n\n return I18nService;\n\n })(taiga.Service);\n\n I18nDirective = function($rootscope, $i18n) {\n var link;\n link = function($scope, $el, $attrs) {\n var ns, options, opts, v, values, _i, _len, _ref, _results;\n values = $attrs.tr.split(\",\");\n options = $attrs.trOpts || '{}';\n opts = $scope.$eval(options);\n _results = [];\n for (_i = 0, _len = values.length; _i < _len; _i++) {\n v = values[_i];\n if (v.indexOf(\":\") === -1) {\n _results.push($el.html(_.escape($i18n.t(v, opts))));\n } else {\n _ref = v.split(\":\"), ns = _ref[0], v = _ref[1];\n _results.push($el.attr(ns, _.escape($i18n.t(v, opts))));\n }\n }\n return _results;\n };\n return {\n link: link,\n restrict: \"A\",\n scope: false\n };\n };\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgI18n\", [\"$rootScope\", \"localesEn\", I18nService]);\n\n module.directive(\"tr\", [\"$rootScope\", \"$tgI18n\", I18nDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/location.coffee\n */\n\n(function() {\n var locationFactory, module;\n\n locationFactory = function($location, $route, $rootscope) {\n $location.noreload = function(scope) {\n var lastRoute, un;\n lastRoute = $route.current;\n un = scope.$on(\"$locationChangeSuccess\", function() {\n $route.current = lastRoute;\n return un();\n });\n return $location;\n };\n return $location;\n };\n\n module = angular.module(\"taigaBase\");\n\n module.factory(\"$tgLocation\", [\"$location\", \"$route\", \"$rootScope\", locationFactory]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/model.coffee\n */\n\n(function() {\n var Model, ModelService, module, provider, taiga,\n __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n Model = (function() {\n function Model(name, data, dataTypes) {\n this._attrs = data;\n this._name = name;\n this._dataTypes = dataTypes;\n this.setAttrs(data);\n this.initialize();\n }\n\n Model.prototype.clone = function() {\n var instance;\n instance = new Model(this._name, this._attrs, this._dataTypes);\n instance._modifiedAttrs = this._modifiedAttrs;\n instance._isModified = this._isModified;\n return instance;\n };\n\n Model.prototype.applyCasts = function() {\n var attrName, castMethod, castName, _ref, _results;\n _ref = this._dataTypes;\n _results = [];\n for (attrName in _ref) {\n castName = _ref[attrName];\n castMethod = service.casts[castName];\n if (!castMethod) {\n continue;\n }\n _results.push(this._attrs[attrName] = castMethod(this._attrs[attrName]));\n }\n return _results;\n };\n\n Model.prototype.getIdAttrName = function() {\n return \"id\";\n };\n\n Model.prototype.getName = function() {\n return this._name;\n };\n\n Model.prototype.getAttrs = function(patch) {\n if (patch == null) {\n patch = false;\n }\n if (this._attrs.version != null) {\n this._modifiedAttrs.version = this._attrs.version;\n }\n if (patch) {\n return _.extend({}, this._modifiedAttrs);\n }\n return _.extend({}, this._attrs, this._modifiedAttrs);\n };\n\n Model.prototype.setAttrs = function(attrs) {\n this._attrs = attrs;\n this._modifiedAttrs = {};\n this.applyCasts();\n return this._isModified = false;\n };\n\n Model.prototype.setAttr = function(name, value) {\n this._modifiedAttrs[name] = value;\n return this._isModified = true;\n };\n\n Model.prototype.initialize = function() {\n var getter, self, setter;\n self = this;\n getter = function(name) {\n return function() {\n if (typeof name === 'string' && name.substr(0, 2) === \"__\") {\n return self[name];\n }\n if (__indexOf.call(_.keys(self._modifiedAttrs), name) < 0) {\n return self._attrs[name];\n }\n return self._modifiedAttrs[name];\n };\n };\n setter = function(name) {\n return function(value) {\n if (typeof name === 'string' && name.substr(0, 2) === \"__\") {\n self[name] = value;\n return;\n }\n if (self._attrs[name] !== value) {\n self._modifiedAttrs[name] = value;\n self._isModified = true;\n } else {\n delete self._modifiedAttrs[name];\n }\n };\n };\n return _.each(this._attrs, function(value, name) {\n var options;\n options = {\n get: getter(name),\n set: setter(name),\n enumerable: true,\n configurable: true\n };\n return Object.defineProperty(self, name, options);\n });\n };\n\n Model.prototype.serialize = function() {\n var data;\n data = {\n \"data\": _.clone(this._attrs),\n \"name\": this._name\n };\n return JSON.stringify(data);\n };\n\n Model.prototype.isModified = function() {\n return this._isModified;\n };\n\n Model.prototype.isAttributeModified = function(attribute) {\n return this._modifiedAttrs[attribute] != null;\n };\n\n Model.prototype.markSaved = function() {\n this._isModified = false;\n this._attrs = this.getAttrs();\n return this._modifiedAttrs = {};\n };\n\n Model.prototype.revert = function() {\n this._modifiedAttrs = {};\n return this._isModified = false;\n };\n\n Model.desSerialize = function(sdata) {\n var ddata, model;\n ddata = JSON.parse(sdata);\n model = new Model(ddata.url, ddata.data);\n return model;\n };\n\n return Model;\n\n })();\n\n taiga = this.taiga;\n\n ModelService = (function(_super) {\n __extends(ModelService, _super);\n\n ModelService.$inject = [\"$q\", \"$tgUrls\", \"$tgStorage\", \"$tgHttp\"];\n\n function ModelService(q, urls, storage, http) {\n this.q = q;\n this.urls = urls;\n this.storage = storage;\n this.http = http;\n ModelService.__super__.constructor.call(this);\n }\n\n return ModelService;\n\n })(taiga.Service);\n\n provider = function($q, $http, $gmUrls, $gmStorage) {\n var service;\n service = {};\n service.make_model = function(name, data, cls, dataTypes) {\n if (cls == null) {\n cls = Model;\n }\n if (dataTypes == null) {\n dataTypes = {};\n }\n return new cls(name, data, dataTypes);\n };\n service.cls = Model;\n service.casts = {\n int: function(value) {\n return parseInt(value, 10);\n },\n float: function(value) {\n return parseFloat(value, 10);\n }\n };\n return service;\n };\n\n module = angular.module(\"taigaBase\");\n\n module.factory(\"$tgModel\", [\"$q\", \"$http\", \"$tgUrls\", \"$tgStorage\", provider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/navurl.coffee\n */\n\n(function() {\n var NavigationUrlsDirective, NavigationUrlsService, bindOnce, module, taiga, trim,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n trim = this.taiga.trim;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaBase\");\n\n NavigationUrlsService = (function(_super) {\n __extends(NavigationUrlsService, _super);\n\n function NavigationUrlsService() {\n this.urls = {};\n }\n\n NavigationUrlsService.prototype.update = function(urls) {\n return this.urls = _.merge({}, this.urls, urls || {});\n };\n\n NavigationUrlsService.prototype.formatUrl = function(url, ctx) {\n var replacer;\n if (ctx == null) {\n ctx = {};\n }\n replacer = function(match) {\n match = trim(match, \":\");\n return ctx[match] || \"undefined\";\n };\n return url.replace(/(:\\w+)/g, replacer);\n };\n\n NavigationUrlsService.prototype.resolve = function(name, ctx) {\n var url;\n url = this.urls[name];\n if (!url) {\n return \"\";\n }\n if (ctx) {\n return this.formatUrl(url, ctx);\n }\n return url;\n };\n\n return NavigationUrlsService;\n\n })(taiga.Service);\n\n module.service(\"$tgNavUrls\", NavigationUrlsService);\n\n NavigationUrlsDirective = function($navurls, $auth, $q, $location) {\n var bindOnceP, link, parseNav;\n bindOnceP = function($scope, attr) {\n var defered;\n defered = $q.defer();\n bindOnce($scope, attr, function(v) {\n return defered.resolve(v);\n });\n return defered.promise;\n };\n parseNav = function(data, $scope) {\n var name, params, promises, values, _ref;\n _ref = _.map(data.split(\":\"), trim), name = _ref[0], params = _ref[1];\n if (params) {\n params = _.map(params.split(\",\"), trim);\n } else {\n params = [];\n }\n values = _.map(params, function(x) {\n return trim(x.split(\"=\")[1]);\n });\n promises = _.map(values, function(x) {\n return bindOnceP($scope, x);\n });\n return $q.all(promises).then(function() {\n var item, key, options, value, _i, _len, _ref1;\n options = {};\n for (_i = 0, _len = params.length; _i < _len; _i++) {\n item = params[_i];\n _ref1 = _.map(item.split(\"=\"), trim), key = _ref1[0], value = _ref1[1];\n options[key] = $scope.$eval(value);\n }\n return [name, options];\n });\n };\n link = function($scope, $el, $attrs) {\n if ($el.is(\"a\")) {\n $el.attr(\"href\", \"#\");\n }\n $el.on(\"mouseenter\", function(event) {\n var target;\n target = $(event.currentTarget);\n if (!target.data(\"fullUrl\")) {\n return parseNav($attrs.tgNav, $scope).then(function(result) {\n var fullUrl, name, options, url, user;\n name = result[0], options = result[1];\n user = $auth.getUser();\n if (user) {\n options.user = user.username;\n }\n url = $navurls.resolve(name);\n fullUrl = $navurls.formatUrl(url, options);\n target.data(\"fullUrl\", fullUrl);\n if (target.is(\"a\")) {\n target.attr(\"href\", fullUrl);\n }\n return $el.on(\"click\", function(event) {\n event.preventDefault();\n target = $(event.currentTarget);\n if (target.hasClass('noclick')) {\n return;\n }\n fullUrl = target.data(\"fullUrl\");\n switch (event.which) {\n case 1:\n $location.url(fullUrl);\n return $scope.$apply();\n case 2:\n return window.open(fullUrl);\n }\n });\n });\n }\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgNav\", [\"$tgNavUrls\", \"$tgAuth\", \"$q\", \"$tgLocation\", NavigationUrlsDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/repository.coffee\n */\n\n(function() {\n var RepositoryService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n RepositoryService = (function(_super) {\n __extends(RepositoryService, _super);\n\n RepositoryService.$inject = [\"$q\", \"$tgModel\", \"$tgStorage\", \"$tgHttp\", \"$tgUrls\"];\n\n function RepositoryService(q, model, storage, http, urls) {\n this.q = q;\n this.model = model;\n this.storage = storage;\n this.http = http;\n this.urls = urls;\n RepositoryService.__super__.constructor.call(this);\n }\n\n RepositoryService.prototype.resolveUrlForModel = function(model) {\n var idAttrName;\n idAttrName = model.getIdAttrName();\n return \"\" + (this.urls.resolve(model.getName())) + \"/\" + model[idAttrName];\n };\n\n RepositoryService.prototype.resolveUrlForAttributeModel = function(model) {\n return this.urls.resolve(model.getName(), model.parent);\n };\n\n RepositoryService.prototype.create = function(name, data, dataTypes, extraParams) {\n var defered, promise, url;\n if (dataTypes == null) {\n dataTypes = {};\n }\n if (extraParams == null) {\n extraParams = {};\n }\n defered = this.q.defer();\n url = this.urls.resolve(name);\n promise = this.http.post(url, JSON.stringify(data));\n promise.success((function(_this) {\n return function(_data, _status) {\n return defered.resolve(_this.model.make_model(name, _data, null, dataTypes));\n };\n })(this));\n promise.error((function(_this) {\n return function(data, status) {\n return defered.reject(data);\n };\n })(this));\n return defered.promise;\n };\n\n RepositoryService.prototype.remove = function(model, params) {\n var defered, promise, url;\n if (params == null) {\n params = {};\n }\n defered = this.q.defer();\n url = this.resolveUrlForModel(model);\n promise = this.http[\"delete\"](url, {}, params);\n promise.success(function(data, status) {\n return defered.resolve(model);\n });\n promise.error(function(data, status) {\n return defered.reject(model);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.saveAll = function(models, patch) {\n var promises;\n if (patch == null) {\n patch = true;\n }\n promises = _.map(models, (function(_this) {\n return function(x) {\n return _this.save(x, true);\n };\n })(this));\n return this.q.all(promises);\n };\n\n RepositoryService.prototype.save = function(model, patch) {\n var data, defered, promise, url;\n if (patch == null) {\n patch = true;\n }\n defered = this.q.defer();\n if (!model.isModified() && patch) {\n defered.resolve(model);\n return defered.promise;\n }\n url = this.resolveUrlForModel(model);\n data = JSON.stringify(model.getAttrs(patch));\n if (patch) {\n promise = this.http.patch(url, data);\n } else {\n promise = this.http.put(url, data);\n }\n promise.success((function(_this) {\n return function(data, status) {\n model._isModified = false;\n model._attrs = _.extend(model.getAttrs(), data);\n model._modifiedAttrs = {};\n model.applyCasts();\n return defered.resolve(model);\n };\n })(this));\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.saveAttribute = function(model, attribute, patch) {\n var data, defered, promise, url;\n if (patch == null) {\n patch = true;\n }\n defered = this.q.defer();\n if (!model.isModified() && patch) {\n defered.resolve(model);\n return defered.promise;\n }\n url = this.resolveUrlForAttributeModel(model);\n data = {};\n data[attribute] = model.getAttrs();\n if (patch) {\n promise = this.http.patch(url, data);\n } else {\n promise = this.http.put(url, data);\n }\n promise.success((function(_this) {\n return function(data, status) {\n model._isModified = false;\n model._attrs = _.extend(model.getAttrs(), data);\n model._modifiedAttrs = {};\n model.applyCasts();\n return defered.resolve(model);\n };\n })(this));\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.refresh = function(model) {\n var defered, promise, url;\n defered = this.q.defer();\n url = this.resolveUrlForModel(model);\n promise = this.http.get(url);\n promise.success(function(data, status) {\n model._modifiedAttrs = {};\n model._attrs = data;\n model._isModified = false;\n model.applyCasts();\n return defered.resolve(model);\n });\n promise.error(function(data, status) {\n return defered.reject(data);\n });\n return defered.promise;\n };\n\n RepositoryService.prototype.queryMany = function(name, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return _.map(data.data, function(x) {\n return _this.model.make_model(name, x);\n });\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOneAttribute = function(name, id, attribute, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name, id);\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n var model;\n model = _this.model.make_model(name, data.data[attribute]);\n model.parent = id;\n return model;\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOne = function(name, id, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n if (id) {\n url = \"\" + url + \"/\" + id;\n }\n httpOptions = {\n headers: {}\n };\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return _this.model.make_model(name, data.data);\n };\n })(this));\n };\n\n RepositoryService.prototype.queryOneRaw = function(name, id, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n if (id) {\n url = \"\" + url + \"/\" + id;\n }\n httpOptions = _.merge({\n headers: {}\n }, options);\n if (!options.enablePagination) {\n httpOptions.headers[\"x-disable-pagination\"] = \"1\";\n }\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n\n RepositoryService.prototype.queryPaginated = function(name, params, options) {\n var httpOptions, url;\n if (options == null) {\n options = {};\n }\n url = this.urls.resolve(name);\n httpOptions = _.merge({\n headers: {}\n }, options);\n return this.http.get(url, params, httpOptions).then((function(_this) {\n return function(data) {\n var headers, result;\n headers = data.headers();\n result = {};\n result.models = _.map(data.data, function(x) {\n return _this.model.make_model(name, x);\n });\n result.count = parseInt(headers[\"x-pagination-count\"], 10);\n result.current = parseInt(headers[\"x-pagination-current\"] || 1, 10);\n result.paginatedBy = parseInt(headers[\"x-paginated-by\"], 10);\n return result;\n };\n })(this));\n };\n\n RepositoryService.prototype.resolve = function(options) {\n var cache, params;\n params = {};\n if (options.pslug != null) {\n params.project = options.pslug;\n }\n if (options.usref != null) {\n params.us = options.usref;\n }\n if (options.taskref != null) {\n params.task = options.taskref;\n }\n if (options.issueref != null) {\n params.issue = options.issueref;\n }\n if (options.sslug != null) {\n params.milestone = options.sslug;\n }\n if (options.wikipage != null) {\n params.wikipage = options.wikipage;\n }\n cache = !(options.wikipage || options.sslug);\n return this.queryOneRaw(\"resolver\", null, params, {\n cache: cache\n });\n };\n\n return RepositoryService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgRepo\", RepositoryService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/storage.coffee\n */\n\n(function() {\n var StorageService, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n StorageService = (function(_super) {\n __extends(StorageService, _super);\n\n StorageService.$inject = [\"$rootScope\"];\n\n function StorageService($rootScope) {\n StorageService.__super__.constructor.call(this);\n }\n\n StorageService.prototype.get = function(key, _default) {\n var serializedValue;\n serializedValue = localStorage.getItem(key);\n if (serializedValue === null) {\n return _default || null;\n }\n return JSON.parse(serializedValue);\n };\n\n StorageService.prototype.set = function(key, val) {\n if (_.isObject(key)) {\n return _.each(key, (function(_this) {\n return function(val, key) {\n return _this.set(key, val);\n };\n })(this));\n } else {\n return localStorage.setItem(key, JSON.stringify(val));\n }\n };\n\n StorageService.prototype.contains = function(key) {\n var value;\n value = this.get(key);\n return value !== null;\n };\n\n StorageService.prototype.remove = function(key) {\n return localStorage.removeItem(key);\n };\n\n StorageService.prototype.clear = function() {\n return localStorage.clear();\n };\n\n return StorageService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service(\"$tgStorage\", StorageService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/base/http.coffee\n */\n\n(function() {\n var UrlsService, format, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n format = function(fmt, obj) {\n obj = _.clone(obj);\n return fmt.replace(/%s/g, function(match) {\n return String(obj.shift());\n });\n };\n\n taiga = this.taiga;\n\n UrlsService = (function(_super) {\n __extends(UrlsService, _super);\n\n UrlsService.$inject = [\"$tgConfig\"];\n\n function UrlsService(config) {\n this.config = config;\n this.urls = {};\n this.mainUrl = config.get(\"api\");\n }\n\n UrlsService.prototype.update = function(urls) {\n return this.urls = _.merge(this.urls, urls);\n };\n\n UrlsService.prototype.resolve = function() {\n var args, name, url;\n args = _.toArray(arguments);\n if (args.length === 0) {\n throw Error(\"wrong arguments to setUrls\");\n }\n name = args.slice(0, 1)[0];\n url = format(this.urls[name], args.slice(1));\n return format(\"%s/%s\", [_.str.rtrim(this.mainUrl, \"/\"), _.str.ltrim(url, \"/\")]);\n };\n\n return UrlsService;\n\n })(taiga.Service);\n\n module = angular.module(\"taigaBase\");\n\n module.service('$tgUrls', UrlsService);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/attachments.coffee\n */\n\n(function() {\n var module, resourceProvider, sizeFormat, taiga;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n resourceProvider = function($rootScope, $config, $urls, $model, $repo, $auth, $q) {\n var service;\n service = {};\n service.list = function(urlName, objectId, projectId) {\n var params;\n params = {\n object_id: objectId,\n project: projectId\n };\n return $repo.queryMany(urlName, params);\n };\n service.create = function(urlName, projectId, objectId, file) {\n var data, defered, maxFileSize, response, uploadComplete, uploadFailed, uploadProgress, xhr;\n defered = $q.defer();\n if (file === void 0) {\n defered.reject(null);\n return defered.promise;\n }\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize && file.size > maxFileSize) {\n response = {\n status: 413,\n data: {\n _error_message: \"'\" + file.name + \"' (\" + (sizeFormat(file.size)) + \") is too heavy for our oompa loompas, try it with a smaller than (\" + (sizeFormat(maxFileSize)) + \")\"\n }\n };\n defered.reject(response);\n return defered.promise;\n }\n uploadProgress = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n file.status = \"in-progress\";\n file.size = sizeFormat(evt.total);\n file.progressMessage = \"upload \" + (sizeFormat(evt.loaded)) + \" of \" + (sizeFormat(evt.total));\n return file.progressPercent = \"\" + (Math.round((evt.loaded / evt.total) * 100)) + \"%\";\n });\n };\n })(this);\n uploadComplete = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n var data, model;\n file.status = \"done\";\n try {\n data = JSON.parse(evt.target.responseText);\n } catch (_error) {\n data = {};\n }\n model = $model.make_model(urlName, data);\n return defered.resolve(model);\n });\n };\n })(this);\n uploadFailed = (function(_this) {\n return function(evt) {\n return $rootScope.$apply(function() {\n file.status = \"error\";\n return defered.reject(\"fail\");\n });\n };\n })(this);\n data = new FormData();\n data.append(\"project\", projectId);\n data.append(\"object_id\", objectId);\n data.append(\"attached_file\", file);\n xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", uploadProgress, false);\n xhr.addEventListener(\"load\", uploadComplete, false);\n xhr.addEventListener(\"error\", uploadFailed, false);\n xhr.open(\"POST\", $urls.resolve(urlName));\n xhr.setRequestHeader(\"Authorization\", \"Bearer \" + ($auth.getToken()));\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send(data);\n return defered.promise;\n };\n return function(instance) {\n return instance.attachments = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgAttachmentsResourcesProvider\", [\"$rootScope\", \"$tgConfig\", \"$tgUrls\", \"$tgModel\", \"$tgRepo\", \"$tgAuth\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/history.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(type, objectId) {\n return $repo.queryOneRaw(\"history/\" + type, objectId);\n };\n service.deleteComment = function(type, objectId, activityId) {\n var params, url;\n url = $urls.resolve(\"history/\" + type);\n url = \"\" + url + \"/\" + objectId + \"/delete_comment\";\n params = {\n id: activityId\n };\n return $http.post(url, null, params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n service.undeleteComment = function(type, objectId, activityId) {\n var params, url;\n url = $urls.resolve(\"history/\" + type);\n url = \"\" + url + \"/\" + objectId + \"/undelete_comment\";\n params = {\n id: activityId\n };\n return $http.post(url, null, params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n return function(instance) {\n return instance.history = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgHistoryResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/projects.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo) {\n var service;\n service = {};\n service.get = function(token) {\n return $repo.queryOne(\"invitations\", token);\n };\n return function(instance) {\n return instance.invitations = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgInvitationsResourcesProvider\", [\"$tgRepo\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/issues.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage, $q) {\n var filtersHashSuffix, hashSuffix, myFiltersHashSuffix, service;\n service = {};\n hashSuffix = \"issues-queryparams\";\n filtersHashSuffix = \"issues-filters\";\n myFiltersHashSuffix = \"issues-my-filters\";\n service.get = function(projectId, issueId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"issues\", issueId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"issues\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.list = function(projectId, filters, options) {\n var params;\n params = {\n project: projectId\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryPaginated(\"issues\", params, options);\n };\n service.bulkCreate = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-create-issues\");\n params = {\n project_id: projectId,\n bulk_issues: data\n };\n return $http.post(url, params);\n };\n service.stats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/issues_stats\");\n };\n service.filtersData = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/issue_filters_data\");\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeFilters = function(projectSlug, params) {\n var hash, ns;\n ns = \"\" + projectSlug + \":\" + filtersHashSuffix;\n hash = generateHash([projectSlug, ns]);\n return $storage.set(hash, params);\n };\n service.getFilters = function(projectSlug) {\n var hash, ns;\n ns = \"\" + projectSlug + \":\" + filtersHashSuffix;\n hash = generateHash([projectSlug, ns]);\n return $storage.get(hash) || {};\n };\n service.storeMyFilters = function(projectId, myFilters) {\n var deferred, hash, ns, promise, url;\n deferred = $q.defer();\n url = $urls.resolve(\"user-storage\");\n ns = \"\" + projectId + \":\" + myFiltersHashSuffix;\n hash = generateHash([projectId, ns]);\n if (_.isEmpty(myFilters)) {\n promise = $http[\"delete\"](\"\" + url + \"/\" + hash, {\n key: hash,\n value: myFilters\n });\n promise.then(function() {\n return deferred.resolve();\n });\n promise.then(null, function() {\n return deferred.reject();\n });\n } else {\n promise = $http.put(\"\" + url + \"/\" + hash, {\n key: hash,\n value: myFilters\n });\n promise.then(function(data) {\n return deferred.resolve();\n });\n promise.then(null, function(data) {\n var innerPromise;\n innerPromise = $http.post(\"\" + url, {\n key: hash,\n value: myFilters\n });\n innerPromise.then(function() {\n return deferred.resolve();\n });\n return innerPromise.then(null, function() {\n return deferred.reject();\n });\n });\n }\n return deferred.promise;\n };\n service.getMyFilters = function(projectId) {\n var deferred, hash, ns, promise, url;\n deferred = $q.defer();\n url = $urls.resolve(\"user-storage\");\n ns = \"\" + projectId + \":\" + myFiltersHashSuffix;\n hash = generateHash([projectId, ns]);\n promise = $http.get(\"\" + url + \"/\" + hash);\n promise.then(function(data) {\n return deferred.resolve(data.data.value);\n });\n promise.then(null, function(data) {\n return deferred.resolve({});\n });\n return deferred.promise;\n };\n return function(instance) {\n return instance.issues = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgIssuesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/kanban.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($storage) {\n var hashSuffixStatusColumnModes, hashSuffixStatusViewModes, service;\n service = {};\n hashSuffixStatusViewModes = \"kanban-statusviewmodels\";\n hashSuffixStatusColumnModes = \"kanban-statuscolumnmodels\";\n service.storeStatusViewModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusViewModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusViewModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusViewModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeStatusColumnModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusColumnModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n return function(instance) {\n return instance.kanban = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgKanbanResourcesProvider\", [\"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/mdrender.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service.render = function(projectId, content) {\n var params, url;\n if ((content == null) || content === \"\") {\n content = ' ';\n }\n params = {\n project_id: projectId,\n content: content\n };\n url = $urls.resolve(\"wiki\");\n return $http.post(\"\" + url + \"/render\", params).then((function(_this) {\n return function(data) {\n return data.data;\n };\n })(this));\n };\n return function(instance) {\n return instance.mdrender = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgMdRenderResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"memberships\", id);\n };\n service.list = function(projectId, filters, enablePagination) {\n var options, params;\n if (enablePagination == null) {\n enablePagination = true;\n }\n params = {\n project: projectId\n };\n params = _.extend({}, params, filters || {});\n if (enablePagination) {\n return $repo.queryPaginated(\"memberships\", params);\n }\n return $repo.queryMany(\"memberships\", params, options = {\n enablePagination: enablePagination\n });\n };\n service.listByUser = function(userId, filters) {\n var params;\n params = {\n user: userId\n };\n params = _.extend({}, params, filters || {});\n return $repo.queryPaginated(\"memberships\", params);\n };\n service.resendInvitation = function(id) {\n var url;\n url = $urls.resolve(\"memberships\");\n return $http.post(\"\" + url + \"/\" + id + \"/resend_invitation\", {});\n };\n service.bulkCreateMemberships = function(projectId, data, invitation_extra_text) {\n var params, url;\n url = $urls.resolve(\"bulk-create-memberships\");\n params = {\n project_id: projectId,\n bulk_memberships: data,\n invitation_extra_text: invitation_extra_text\n };\n return $http.post(url, params);\n };\n return function(instance) {\n return instance.memberships = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgMembershipsResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n(function() {\n var module, resourceProvider;\n\n resourceProvider = function($repo) {\n var service;\n service = {};\n service.list = function(projectId, module) {\n return $repo.queryOneAttribute(\"project-modules\", projectId, module);\n };\n return function(instance) {\n return instance.modules = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgModulesResourcesProvider\", [\"$tgRepo\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"notify-policies\", id);\n };\n service.list = function(filters) {\n var params;\n params = _.extend({}, params, filters || {});\n return $repo.queryMany(\"notify-policies\", params);\n };\n return function(instance) {\n return instance.notifyPolicies = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgNotifyPoliciesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/projects.coffee\n */\n\n(function() {\n var module, resourceProvider, sizeFormat, taiga;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n resourceProvider = function($config, $repo, $http, $urls, $auth, $q, $rootScope) {\n var service;\n service = {};\n service.get = function(projectId) {\n return $repo.queryOne(\"projects\", projectId);\n };\n service.getBySlug = function(projectSlug) {\n return $repo.queryOne(\"projects\", \"by_slug?slug=\" + projectSlug);\n };\n service.list = function() {\n return $repo.queryMany(\"projects\");\n };\n service.templates = function() {\n return $repo.queryMany(\"project-templates\");\n };\n service.usersList = function(projectId) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(\"users\", params);\n };\n service.rolesList = function(projectId) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(\"roles\", params);\n };\n service.stats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/stats\");\n };\n service.leave = function(projectId) {\n var url;\n url = \"\" + ($urls.resolve(\"projects\")) + \"/\" + projectId + \"/leave\";\n return $http.post(url);\n };\n service.memberStats = function(projectId) {\n return $repo.queryOneRaw(\"projects\", \"\" + projectId + \"/member_stats\");\n };\n service.tagsColors = function(projectId) {\n return $repo.queryOne(\"projects\", \"\" + projectId + \"/tags_colors\");\n };\n service[\"export\"] = function(projectId) {\n var url;\n url = \"\" + ($urls.resolve(\"exporter\")) + \"/\" + projectId;\n return $http.get(url);\n };\n service[\"import\"] = function(file, statusUpdater) {\n var complete, data, defered, failed, maxFileSize, response, uploadComplete, uploadFailed, uploadProgress, xhr;\n defered = $q.defer();\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize && file.size > maxFileSize) {\n response = {\n status: 413,\n data: {\n _error_message: \"'\" + file.name + \"' (\" + (sizeFormat(file.size)) + \") is too heavy for our oompa loompas, try it with a smaller than (\" + (sizeFormat(maxFileSize)) + \")\"\n }\n };\n defered.reject(response);\n return defered.promise;\n }\n uploadProgress = (function(_this) {\n return function(evt) {\n var message, percent;\n percent = Math.round((evt.loaded / evt.total) * 100);\n message = \"Uloaded \" + (sizeFormat(evt.loaded)) + \" of \" + (sizeFormat(evt.total));\n return statusUpdater(\"in-progress\", null, message, percent);\n };\n })(this);\n uploadComplete = (function(_this) {\n return function(evt) {\n return statusUpdater(\"done\", \"Importing Project\", \"This process can take a while, please keep the window open.\");\n };\n })(this);\n uploadFailed = (function(_this) {\n return function(evt) {\n return statusUpdater(\"error\");\n };\n })(this);\n complete = (function(_this) {\n return function(evt) {\n var _ref;\n response = {};\n try {\n response.data = JSON.parse(evt.target.responseText);\n } catch (_error) {\n response.data = {};\n }\n response.status = evt.target.status;\n if ((_ref = response.status) === 201 || _ref === 202) {\n defered.resolve(response);\n }\n return defered.reject(response);\n };\n })(this);\n failed = (function(_this) {\n return function(evt) {\n return defered.reject(\"fail\");\n };\n })(this);\n data = new FormData();\n data.append('dump', file);\n xhr = new XMLHttpRequest();\n xhr.upload.addEventListener(\"progress\", uploadProgress, false);\n xhr.upload.addEventListener(\"load\", uploadComplete, false);\n xhr.upload.addEventListener(\"error\", uploadFailed, false);\n xhr.upload.addEventListener(\"abort\", uploadFailed, false);\n xhr.addEventListener(\"load\", complete, false);\n xhr.addEventListener(\"error\", failed, false);\n xhr.open(\"POST\", $urls.resolve(\"importer\"));\n xhr.setRequestHeader(\"Authorization\", \"Bearer \" + ($auth.getToken()));\n xhr.setRequestHeader('Accept', 'application/json');\n xhr.send(data);\n return defered.promise;\n };\n return function(instance) {\n return instance.projects = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgProjectsResourcesProvider\", [\"$tgConfig\", \"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgAuth\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(id) {\n return $repo.queryOne(\"roles\", id);\n };\n service.list = function(projectId) {\n return $repo.queryMany(\"roles\", {\n project: projectId\n });\n };\n return function(instance) {\n return instance.roles = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgRolesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/search.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service[\"do\"] = function(projectId, term) {\n var params, url;\n url = $urls.resolve(\"search\");\n params = {\n project: projectId,\n text: term,\n get_all: false\n };\n return $http.get(url, params).then(function(data) {\n return data.data;\n });\n };\n return function(instance) {\n return instance.search = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgSearchResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/sprints.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $model, $storage) {\n var hashSuffixUserstories, service;\n service = {};\n hashSuffixUserstories = \"userstories-queryparams\";\n service.get = function(projectId, sprintId) {\n return $repo.queryOne(\"milestones\", sprintId).then(function(sprint) {\n var uses;\n service.storeUserstoriesQueryParams(projectId, {\n \"milestone\": sprintId\n });\n uses = sprint.user_stories;\n uses = _.map(uses, function(u) {\n return $model.make_model(\"userstories\", u);\n });\n sprint._attrs.user_stories = uses;\n return sprint;\n });\n };\n service.stats = function(projectId, sprintId) {\n return $repo.queryOneRaw(\"milestones\", \"\" + sprintId + \"/stats\");\n };\n service.list = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId\n };\n params = _.extend({}, params, filters || {});\n return $repo.queryMany(\"milestones\", params).then((function(_this) {\n return function(milestones) {\n var m, uses, _i, _len;\n for (_i = 0, _len = milestones.length; _i < _len; _i++) {\n m = milestones[_i];\n uses = m.user_stories;\n uses = _.map(uses, function(u) {\n return $model.make_model(\"userstories\", u);\n });\n m._attrs.user_stories = uses;\n }\n return milestones;\n };\n })(this));\n };\n service.storeUserstoriesQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUserstories;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n return function(instance) {\n return instance.sprints = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgSprintsResourcesProvider\", [\"$tgRepo\", \"$tgModel\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/tasks.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage) {\n var hashSuffix, hashSuffixStatusColumnModes, hashSuffixUsRowModes, service;\n service = {};\n hashSuffix = \"tasks-queryparams\";\n hashSuffixStatusColumnModes = \"tasks-statuscolumnmodels\";\n hashSuffixUsRowModes = \"tasks-usrowmodels\";\n service.get = function(projectId, taskId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"tasks\", taskId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"tasks\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.list = function(projectId, sprintId, userStoryId) {\n var params;\n if (sprintId == null) {\n sprintId = null;\n }\n if (userStoryId == null) {\n userStoryId = null;\n }\n params = {\n project: projectId\n };\n if (sprintId) {\n params.milestone = sprintId;\n }\n if (userStoryId) {\n params.user_story = userStoryId;\n }\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"tasks\", params);\n };\n service.bulkCreate = function(projectId, sprintId, usId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-create-tasks\");\n params = {\n project_id: projectId,\n sprint_id: sprintId,\n us_id: usId,\n bulk_tasks: data\n };\n return $http.post(url, params).then(function(result) {\n return result.data;\n });\n };\n service.bulkUpdateTaskTaskboardOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-task-taskboard-order\");\n params = {\n project_id: projectId,\n bulk_tasks: data\n };\n return $http.post(url, params);\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeStatusColumnModes = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getStatusColumnModes = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixStatusColumnModes;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeUsRowModes = function(projectId, sprintId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUsRowModes;\n hash = generateHash([projectId, sprintId, ns]);\n return $storage.set(hash, params);\n };\n service.getUsRowModes = function(projectId, sprintId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffixUsRowModes;\n hash = generateHash([projectId, sprintId, ns]);\n return $storage.get(hash) || {};\n };\n return function(instance) {\n return instance.tasks = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgTasksResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/memberships.coffee\n */\n\n(function() {\n var module, resourceProvider, sizeFormat, taiga;\n\n taiga = this.taiga;\n\n sizeFormat = this.taiga.sizeFormat;\n\n resourceProvider = function($config, $repo, $http, $urls, $q) {\n var service;\n service = {};\n service.changeAvatar = function(file) {\n var data, defered, maxFileSize, options, response, url;\n maxFileSize = $config.get(\"maxUploadFileSize\", null);\n if (maxFileSize && file.size > maxFileSize) {\n response = {\n status: 413,\n data: {\n _error_message: \"'\" + file.name + \"' (\" + (sizeFormat(file.size)) + \") is too heavy for our oompa loompas, try it with a smaller than (\" + (sizeFormat(maxFileSize)) + \")\"\n }\n };\n defered = $q.defer();\n defered.reject(response);\n return defered.promise;\n }\n data = new FormData();\n data.append('avatar', file);\n options = {\n transformRequest: angular.identity,\n headers: {\n 'Content-Type': void 0\n }\n };\n url = \"\" + ($urls.resolve(\"users\")) + \"/change_avatar\";\n return $http.post(url, data, {}, options);\n };\n service.removeAvatar = function() {\n var url;\n url = \"\" + ($urls.resolve(\"users\")) + \"/remove_avatar\";\n return $http.post(url);\n };\n service.changePassword = function(currentPassword, newPassword) {\n var data, url;\n url = \"\" + ($urls.resolve(\"users\")) + \"/change_password\";\n data = {\n current_password: currentPassword,\n password: newPassword\n };\n return $http.post(url, data);\n };\n return function(instance) {\n return instance.userSettings = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgUserSettingsResourcesProvider\", [\"$tgConfig\", \"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$q\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/userstories.coffee\n */\n\n(function() {\n var generateHash, module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n generateHash = taiga.generateHash;\n\n resourceProvider = function($repo, $http, $urls, $storage) {\n var hashSuffix, service;\n service = {};\n hashSuffix = \"userstories-queryparams\";\n service.get = function(projectId, usId) {\n var params;\n params = service.getQueryParams(projectId);\n params.project = projectId;\n return $repo.queryOne(\"userstories\", usId, params);\n };\n service.getByRef = function(projectId, ref) {\n return $repo.queryOne(\"userstories\", \"by_ref?project=\" + projectId + \"&ref=\" + ref);\n };\n service.listUnassigned = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId,\n \"milestone\": \"null\"\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"userstories\", params);\n };\n service.listAll = function(projectId, filters) {\n var params;\n params = {\n \"project\": projectId\n };\n params = _.extend({}, params, filters || {});\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(\"userstories\", params);\n };\n service.bulkCreate = function(projectId, status, bulk) {\n var data, url;\n data = {\n project_id: projectId,\n status_id: status,\n bulk_stories: bulk\n };\n url = $urls.resolve(\"bulk-create-us\");\n return $http.post(url, data);\n };\n service.bulkUpdateBacklogOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-backlog-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.bulkUpdateSprintOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-sprint-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.bulkUpdateKanbanOrder = function(projectId, data) {\n var params, url;\n url = $urls.resolve(\"bulk-update-us-kanban-order\");\n params = {\n project_id: projectId,\n bulk_stories: data\n };\n return $http.post(url, params);\n };\n service.listValues = function(projectId, type) {\n var params;\n params = {\n \"project\": projectId\n };\n service.storeQueryParams(projectId, params);\n return $repo.queryMany(type, params);\n };\n service.storeQueryParams = function(projectId, params) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.set(hash, params);\n };\n service.getQueryParams = function(projectId) {\n var hash, ns;\n ns = \"\" + projectId + \":\" + hashSuffix;\n hash = generateHash([projectId, ns]);\n return $storage.get(hash) || {};\n };\n service.storeShowTags = function(projectId, showTags) {\n var hash;\n hash = generateHash([projectId, 'showTags']);\n return $storage.set(hash, showTags);\n };\n service.getShowTags = function(projectId) {\n var hash;\n hash = generateHash([projectId, 'showTags']);\n return $storage.get(hash) || null;\n };\n return function(instance) {\n return instance.userstories = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgUserstoriesResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", \"$tgStorage\", resourceProvider]);\n\n}).call(this);\n\n(function() {\n var module, resourceProvider;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service.list = function(webhookId) {\n var params;\n params = {\n webhook: webhookId\n };\n return $repo.queryMany(\"webhooklogs\", params);\n };\n service.resend = function(webhooklogId) {\n var url;\n url = $urls.resolve(\"webhooklogs-resend\", webhooklogId);\n return $http.post(url);\n };\n return function(instance) {\n return instance.webhooklogs = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgWebhookLogsResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n(function() {\n var module, resourceProvider;\n\n resourceProvider = function($repo, $urls, $http) {\n var service;\n service = {};\n service.list = function(projectId) {\n var params;\n params = {\n project: projectId\n };\n return $repo.queryMany(\"webhooks\", params);\n };\n service.test = function(webhookId) {\n var url;\n url = $urls.resolve(\"webhooks-test\", webhookId);\n return $http.post(url);\n };\n return function(instance) {\n return instance.webhooks = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgWebhooksResourcesProvider\", [\"$tgRepo\", \"$tgUrls\", \"$tgHttp\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/resources/wikis.coffee\n */\n\n(function() {\n var module, resourceProvider, taiga;\n\n taiga = this.taiga;\n\n resourceProvider = function($repo, $http, $urls) {\n var service;\n service = {};\n service.get = function(wikiId) {\n return $repo.queryOne(\"wiki\", wikiId);\n };\n service.getBySlug = function(projectId, slug) {\n return $repo.queryOne(\"wiki\", \"by_slug?project=\" + projectId + \"&slug=\" + slug);\n };\n service.listLinks = function(projectId) {\n return $repo.queryMany(\"wiki-links\", {\n project: projectId\n });\n };\n return function(instance) {\n return instance.wiki = service;\n };\n };\n\n module = angular.module(\"taigaResources\");\n\n module.factory(\"$tgWikiResourcesProvider\", [\"$tgRepo\", \"$tgHttp\", \"$tgUrls\", resourceProvider]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/main.coffee\n */\n\n(function() {\n var UserChangePasswordController, UserChangePasswordDirective, debounce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaUserSettings\");\n\n UserChangePasswordController = (function(_super) {\n __extends(UserChangePasswordController, _super);\n\n UserChangePasswordController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserChangePasswordController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, auth) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"Change Password\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserChangePasswordController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserChangePasswordController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n return UserChangePasswordController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserChangePasswordController\", UserChangePasswordController);\n\n UserChangePasswordDirective = function($rs, $confirm, $loading) {\n var link;\n link = function($scope, $el, $attrs, ctrl) {\n var submit, submitButton;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var promise;\n event.preventDefault();\n if ($scope.newPassword1 !== $scope.newPassword2) {\n $confirm.notify('error', \"The passwords dosn't match\");\n return;\n }\n $loading.start(submitButton);\n promise = $rs.userSettings.changePassword($scope.currentPassword, $scope.newPassword1);\n promise.then(function() {\n $loading.finish(submitButton);\n return $confirm.notify('success');\n });\n return promise.then(null, function(response) {\n $loading.finish(submitButton);\n return $confirm.notify('error', response.data._error_message);\n });\n };\n })(this));\n submitButton = $el.find(\".submit-button\");\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserChangePassword\", [\"$tgResources\", \"$tgConfirm\", \"$tgLoading\", UserChangePasswordDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/issues/lightboxes.coffee\n */\n\n(function() {\n var DeleteUserDirective, bindOnce, debounce, module, taiga;\n\n taiga = this.taiga;\n\n bindOnce = this.taiga.bindOnce;\n\n debounce = this.taiga.debounce;\n\n module = angular.module(\"taigaUserSettings\");\n\n DeleteUserDirective = function($repo, $rootscope, $auth, $location, $navUrls, lightboxService) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit;\n $scope.$on(\"deletelightbox:new\", function(ctx, user) {\n return lightboxService.open($el);\n });\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n submit = function() {\n var promise;\n promise = $repo.remove($scope.user);\n promise.then(function(data) {\n lightboxService.close($el);\n $auth.logout();\n return $location.path($navUrls.resolve(\"login\"));\n });\n return promise.then(null, function() {\n return console.log(\"FAIL\");\n });\n };\n $el.on(\"click\", \".button-red\", function(event) {\n event.preventDefault();\n return lightboxService.close($el);\n });\n return $el.on(\"click\", \".button-green\", debounce(2000, function(event) {\n event.preventDefault();\n return submit();\n }));\n };\n return {\n link: link,\n templateUrl: \"user/lightbox/lightbox-delete-account.html\"\n };\n };\n\n module.directive(\"tgLbDeleteUser\", [\"$tgRepo\", \"$rootScope\", \"$tgAuth\", \"$tgLocation\", \"$tgNavUrls\", \"lightboxService\", DeleteUserDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/main.coffee\n */\n\n(function() {\n var TaigaAvatarModelDirective, UserAvatarDirective, UserProfileDirective, UserSettingsController, debounce, mixOf, module, sizeFormat, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n sizeFormat = this.taiga.sizeFormat;\n\n module = angular.module(\"taigaUserSettings\");\n\n debounce = this.taiga.debounce;\n\n UserSettingsController = (function(_super) {\n __extends(UserSettingsController, _super);\n\n UserSettingsController.$inject = [\"$scope\", \"$rootScope\", \"$tgConfig\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserSettingsController(scope, rootscope, config, repo, confirm, rs, params, q, location, navUrls, auth) {\n var maxFileSize, promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.config = config;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"User Profile\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n maxFileSize = this.config.get(\"maxUploadFileSize\", null);\n if (maxFileSize) {\n this.scope.maxFileSizeMsg = \"[Max, size: \" + (sizeFormat(maxFileSize));\n }\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserSettingsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserSettingsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this));\n };\n\n UserSettingsController.prototype.openDeleteLightbox = function() {\n return this.rootscope.$broadcast(\"deletelightbox:new\", this.scope.user);\n };\n\n return UserSettingsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserSettingsController\", UserSettingsController);\n\n UserProfileDirective = function($confirm, $auth, $repo) {\n var link;\n link = function($scope, $el, $attrs) {\n var submit;\n submit = debounce(2000, (function(_this) {\n return function(event) {\n var changeEmail, form, onError, onSuccess;\n event.preventDefault();\n form = $el.find(\"form\").checksley();\n if (!form.validate()) {\n return;\n }\n changeEmail = $scope.user.isAttributeModified(\"email\");\n onSuccess = function(data) {\n $auth.setUser($scope.user);\n if (changeEmail) {\n return $confirm.success(\"Check your inbox!
    We have sent a mail to your account
    with the instructions to set your new address\");\n } else {\n return $confirm.notify('success');\n }\n };\n onError = function(data) {\n form.setErrors(data);\n return $confirm.notify('error', data._error_message);\n };\n return $repo.save($scope.user).then(onSuccess, onError);\n };\n })(this));\n $el.on(\"submit\", \"form\", submit);\n $el.on(\"click\", \".submit-button\", submit);\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserProfile\", [\"$tgConfirm\", \"$tgAuth\", \"$tgRepo\", UserProfileDirective]);\n\n UserAvatarDirective = function($auth, $model, $rs, $confirm) {\n var link;\n link = function($scope, $el, $attrs) {\n var onError, onSuccess, showSizeInfo;\n showSizeInfo = function() {\n return $el.find(\".size-info\").removeClass(\"hidden\");\n };\n onSuccess = function(response) {\n var user;\n user = $model.make_model(\"users\", response.data);\n $auth.setUser(user);\n $scope.user = user;\n $el.find('.overlay').hide();\n return $confirm.notify('success');\n };\n onError = function(response) {\n if (response.status === 413) {\n showSizeInfo();\n }\n $el.find('.overlay').hide();\n return $confirm.notify('error', response.data._error_message);\n };\n $el.on(\"click\", \".button.change\", function() {\n return $el.find(\"#avatar-field\").click();\n });\n $el.on(\"change\", \"#avatar-field\", function(event) {\n if ($scope.avatarAttachment) {\n $el.find('.overlay').css('display', 'flex');\n return $rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess, onError);\n }\n });\n $el.on(\"click\", \"a.use-gravatar\", function(event) {\n $el.find('.overlay').show();\n return $rs.userSettings.removeAvatar().then(onSuccess, onError);\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserAvatar\", [\"$tgAuth\", \"$tgModel\", \"$tgResources\", \"$tgConfirm\", UserAvatarDirective]);\n\n TaigaAvatarModelDirective = function($parse) {\n var link;\n link = function($scope, $el, $attrs) {\n var model, modelSetter;\n model = $parse($attrs.tgAvatarModel);\n modelSetter = model.assign;\n return $el.bind('change', function() {\n return $scope.$apply(function() {\n return modelSetter($scope, $el[0].files[0]);\n });\n });\n };\n return {\n link: link\n };\n };\n\n module.directive('tgAvatarModel', ['$parse', TaigaAvatarModelDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/nav.coffee\n */\n\n(function() {\n var UserSettingsNavigationDirective, module;\n\n UserSettingsNavigationDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n var section;\n section = $attrs.tgUserSettingsNavigation;\n $el.find(\".active\").removeClass(\"active\");\n $el.find(\"#usersettingsmenu-\" + section + \" a\").addClass(\"active\");\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module = angular.module(\"taigaUserSettings\");\n\n module.directive(\"tgUserSettingsNavigation\", UserSettingsNavigationDirective);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/user-settings/notifications.coffee\n */\n\n(function() {\n var UserNotificationsController, UserNotificationsDirective, UserNotificationsListDirective, bindOnce, mixOf, module, taiga,\n __hasProp = {}.hasOwnProperty,\n __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };\n\n taiga = this.taiga;\n\n mixOf = this.taiga.mixOf;\n\n bindOnce = this.taiga.bindOnce;\n\n module = angular.module(\"taigaUserSettings\");\n\n UserNotificationsController = (function(_super) {\n __extends(UserNotificationsController, _super);\n\n UserNotificationsController.$inject = [\"$scope\", \"$rootScope\", \"$tgRepo\", \"$tgConfirm\", \"$tgResources\", \"$routeParams\", \"$q\", \"$tgLocation\", \"$tgNavUrls\", \"$tgAuth\"];\n\n function UserNotificationsController(scope, rootscope, repo, confirm, rs, params, q, location, navUrls, auth) {\n var promise;\n this.scope = scope;\n this.rootscope = rootscope;\n this.repo = repo;\n this.confirm = confirm;\n this.rs = rs;\n this.params = params;\n this.q = q;\n this.location = location;\n this.navUrls = navUrls;\n this.auth = auth;\n this.scope.sectionName = \"Email Notifications\";\n this.scope.project = {};\n this.scope.user = this.auth.getUser();\n promise = this.loadInitialData();\n promise.then(null, this.onInitialDataError.bind(this));\n }\n\n UserNotificationsController.prototype.loadProject = function() {\n return this.rs.projects.get(this.scope.projectId).then((function(_this) {\n return function(project) {\n _this.scope.project = project;\n _this.scope.$emit('project:loaded', project);\n return project;\n };\n })(this));\n };\n\n UserNotificationsController.prototype.loadNotifyPolicies = function() {\n return this.rs.notifyPolicies.list().then((function(_this) {\n return function(notifyPolicies) {\n _this.scope.notifyPolicies = notifyPolicies;\n return notifyPolicies;\n };\n })(this));\n };\n\n UserNotificationsController.prototype.loadInitialData = function() {\n var promise;\n promise = this.repo.resolve({\n pslug: this.params.pslug\n }).then((function(_this) {\n return function(data) {\n _this.scope.projectId = data.project;\n return data;\n };\n })(this));\n return promise.then((function(_this) {\n return function() {\n return _this.loadProject();\n };\n })(this)).then((function(_this) {\n return function() {\n return _this.loadNotifyPolicies();\n };\n })(this));\n };\n\n return UserNotificationsController;\n\n })(mixOf(taiga.Controller, taiga.PageMixin));\n\n module.controller(\"UserNotificationsController\", UserNotificationsController);\n\n UserNotificationsDirective = function() {\n var link;\n link = function($scope, $el, $attrs) {\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserNotifications\", UserNotificationsDirective);\n\n UserNotificationsListDirective = function($repo, $confirm) {\n var link, template;\n template = _.template(\"<% _.each(notifyPolicies, function (notifyPolicy, index) { %>\\n
    \\\">\\n
    <%- notifyPolicy.project_name %>
    \\n
    \\n
    \\n \\\" id=\\\"policy-all-<%- notifyPolicy.id %>\\\"\\n value=\\\"2\\\" <% if (notifyPolicy.notify_level == 2) { %>checked=\\\"checked\\\"<% } %>/>\\n \\n
    \\n
    \\n
    \\n
    \\n \\\" id=\\\"policy-involved-<%- notifyPolicy.id %>\\\"\\n value=\\\"1\\\" <% if (notifyPolicy.notify_level == 1) { %>checked=\\\"checked\\\"<% } %> />\\n \\n
    \\n
    \\n
    \\n
    \\n \\\" id=\\\"policy-none-<%- notifyPolicy.id %>\\\"\\n value=\\\"3\\\" <% if (notifyPolicy.notify_level == 3) { %>checked=\\\"checked\\\"<% } %> />\\n \\n
    \\n
    \\n
    \\n<% }) %>\");\n link = function($scope, $el, $attrs) {\n var render;\n render = function() {\n $el.off();\n $el.html(template({\n notifyPolicies: $scope.notifyPolicies\n }));\n return $el.on(\"change\", \"input[type=radio]\", function(event) {\n var onError, onSuccess, policy, policyIndex, prev_level, target;\n target = angular.element(event.currentTarget);\n policyIndex = target.parents(\".policy-table-row\").data('index');\n policy = $scope.notifyPolicies[policyIndex];\n prev_level = policy.notify_level;\n policy.notify_level = parseInt(target.val(), 10);\n onSuccess = function() {\n return $confirm.notify(\"success\");\n };\n onError = function() {\n $confirm.notify(\"error\");\n return target.parents(\".policy-table-row\").find(\"input[value=\" + prev_level + \"]\").prop(\"checked\", true);\n };\n return $repo.save(policy).then(onSuccess, onError);\n });\n };\n $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n return bindOnce($scope, $attrs.ngModel, render);\n };\n return {\n link: link\n };\n };\n\n module.directive(\"tgUserNotificationsList\", [\"$tgRepo\", \"$tgConfirm\", UserNotificationsListDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: modules/integrations/github.coffee\n */\n\n(function() {\n var AUTH_URL, GithubLoginButtonDirective, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaIntegrations\");\n\n AUTH_URL = \"https://github.com/login/oauth/authorize\";\n\n GithubLoginButtonDirective = function($window, $params, $location, $config, $events, $confirm, $auth, $navUrls, $loader) {\n var link, template;\n template = \"
    \\n \\n Login with Github\\n\";\n link = function($scope, $el, $attrs) {\n var clientId, loginOnError, loginOnSuccess, loginWithGitHubAccount, renderGitHubButton;\n clientId = $config.get(\"gitHubClientId\", null);\n if (!clientId) {\n return;\n }\n renderGitHubButton = function() {\n if (clientId) {\n return $el.html(template);\n }\n };\n loginOnSuccess = function(response) {\n var nextUrl;\n if ($params.next && $params.next !== $navUrls.resolve(\"login\")) {\n nextUrl = $params.next;\n } else {\n nextUrl = $navUrls.resolve(\"home\");\n }\n $events.setupConnection();\n $location.search(\"next\", null);\n $location.search(\"token\", null);\n $location.search(\"state\", null);\n $location.search(\"code\", null);\n return $location.path(nextUrl);\n };\n loginOnError = function(response) {\n $location.search(\"state\", null);\n $location.search(\"code\", null);\n $loader.pageLoaded();\n if (response.data.error_message) {\n return $confirm.notify(\"light-error\", response.data.error_message);\n } else {\n return $confirm.notify(\"light-error\", \"Our Oompa Loompas have not been able to get you credentials from GitHub.\");\n }\n };\n loginWithGitHubAccount = function() {\n var code, data, token, type;\n type = $params.state;\n code = $params.code;\n token = $params.token;\n if (!(type === \"github\" && code)) {\n return;\n }\n $loader.start();\n data = {\n code: code,\n token: token\n };\n return $auth.login(data, type).then(loginOnSuccess, loginOnError);\n };\n renderGitHubButton();\n loginWithGitHubAccount();\n $el.on(\"click\", \".button-github\", function(event) {\n var redirectToUri, url;\n redirectToUri = $location.absUrl();\n url = \"\" + AUTH_URL + \"?client_id=\" + clientId + \"&redirect_uri=\" + redirectToUri + \"&state=github&scope=user:email\";\n return $window.location.href = url;\n });\n return $scope.$on(\"$destroy\", function() {\n return $el.off();\n });\n };\n return {\n link: link,\n restrict: \"EA\",\n template: \"\"\n };\n };\n\n module.directive(\"tgGithubLoginButton\", [\"$window\", '$routeParams', \"$tgLocation\", \"$tgConfig\", \"$tgEvents\", \"$tgConfirm\", \"$tgAuth\", \"$tgNavUrls\", \"tgLoader\", GithubLoginButtonDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: plugins/humanshtml/humanshtml.coffee\n */\n\n(function() {\n var configure, module, taiga;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n configure = function($routeProvider) {\n return $routeProvider.when(\"/humans.html\", {\n \"templateUrl\": \"/plugins/humanshtml/templates/humans.html\"\n });\n };\n\n module.config([\"$routeProvider\", configure]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: plugins/terms/terms.coffee\n */\n\n(function() {\n var TermsNoticeDirective, module, taiga, template;\n\n taiga = this.taiga;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n template = _.template(\"

    \\n By clicking \\\"Sign up\\\", you agree to our
    \\n \\\" title=\\\"See terms of service\\\" target=\\\"_blank\\\"> terms of service\\n and\\n \\\" title=\\\"See privacy policy\\\" target=\\\"_blank\\\"> privacy policy.\\n

    \");\n\n TermsNoticeDirective = function($config) {\n var privacyPolicyUrl, templateFn, termsOfServiceUrl;\n privacyPolicyUrl = $config.get(\"privacyPolicyUrl\");\n termsOfServiceUrl = $config.get(\"termsOfServiceUrl\");\n templateFn = function() {\n var ctx;\n if (!(privacyPolicyUrl && termsOfServiceUrl)) {\n return \"\";\n }\n ctx = {\n termsUrl: termsOfServiceUrl,\n privacyUrl: privacyPolicyUrl\n };\n return template(ctx);\n };\n return {\n scope: {},\n restrict: \"AE\",\n template: templateFn\n };\n };\n\n module.directive(\"tgTermsNotice\", [\"$tgConfig\", TermsNoticeDirective]);\n\n}).call(this);\n\n\n/*\n * Copyright (C) 2014 Andrey Antukh \n * Copyright (C) 2014 Jesús Espino Garcia \n * Copyright (C) 2014 David Barragán Merino \n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see .\n *\n * File: pluggins/main.coffee\n */\n\n(function() {\n var module;\n\n module = angular.module(\"taigaPlugins\", [\"ngRoute\"]);\n\n}).call(this);\n","angular.module('taigaBase').value('localesEn', {\n \"checksley\": {\n \"defaultMessage\": \"This value seems to be invalid.\",\n \"type-email\": \"This value should be a valid email.\",\n \"type-url\": \"This value should be a valid url.\",\n \"type-urlstrict\": \"This value should be a valid url.\",\n \"type-number\": \"This value should be a valid number.\",\n \"type-digits\": \"This value should be digits.\",\n \"type-dateIso\": \"This value should be a valid date (YYYY-MM-DD).\",\n \"type-alphanum\": \"This value should be alphanumeric.\",\n \"type-phone\": \"This value should be a valid phone number.\",\n \"notnull\": \"This value should not be null.\",\n \"notblank\": \"This value should not be blank.\",\n \"required\": \"This value is required.\",\n \"regexp\": \"This value seems to be invalid.\",\n \"min\": \"This value should be greater than or equal to %s.\",\n \"max\": \"This value should be lower than or equal to %s.\",\n \"range\": \"This value should be between %s and %s.\",\n \"minlength\": \"This value is too short. It should have %s characters or more.\",\n \"maxlength\": \"This value is too long. It should have %s characters or less.\",\n \"rangelength\": \"This value length is invalid. It should be between %s and %s characters long.\",\n \"mincheck\": \"You must select at least %s choices.\",\n \"maxcheck\": \"You must select %s choices or less.\",\n \"rangecheck\": \"You must select between %s and %s choices.\",\n \"equalto\": \"This value should be the same.\"\n },\n \"common\": {\n \"subject\": \"Subject\",\n \"save\": \"Save\",\n \"blocked\": \"Blocked\",\n \"cancel\": \"Cancel\",\n \"status\": \"Status\",\n \"new-bulk\": \"New bulk insert\",\n \"one-item-line\": \"One item per line...\"\n },\n \"pagination\": {\n \"next\": \"Next\",\n \"prev\": \"Previous\"\n },\n \"markdown-editor\": {\n \"heading-1\": \"First Level Heading\",\n \"heading-2\": \"Second Level Heading\",\n \"heading-3\": \"Third Level Heading\",\n \"bold\": \"Bold\",\n \"italic\": \"Italic\",\n \"strike\": \"Strike\",\n \"bulleted-list\": \"Bulleted List\",\n \"numeric-list\": \"Numeric List\",\n \"picture\": \"Picture\",\n \"link\": \"Link\",\n \"quotes\": \"Quotes\",\n \"code-block\": \"Code Block / Code\",\n \"preview\": \"Preview\",\n \"help\": \"Help\",\n \"placeholder\": \"Your title here...\",\n \"link-placeholder\": \"Your text to link here...\"\n },\n \"us\": {\n \"title-new\": \"New User Story\",\n \"team-requirement\": \"Team Requirement\",\n \"client-requirement\": \"Client Requirement\"\n }\n}\n);"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/dist/js/templates.js b/dist/js/templates.js new file mode 100644 index 0000000..656d503 --- /dev/null +++ b/dist/js/templates.js @@ -0,0 +1,128 @@ +angular.module("templates", []).run(["$templateCache", function($templateCache) {$templateCache.put("admin/admin-membership-paginator.html","\n
      <% if (showPrevious) { %>\n
    • Prev
    • <% } %>\n <% _.each(pages, function(item) { %>\n
    • \"><% if (item.type === \"page\") { %>\"><%- item.num %><% } else if (item.type === \"page-active\") { %><%- item.num %><% } else { %>...<% } %>
    • <% }); %>\n <% if (showNext) { %>\n
    • Next
    • <% } %>\n
    "); +$templateCache.put("admin/admin-memberships-row-checkbox.html","\n
    \n \"/>\n
    YesNo\n
    "); +$templateCache.put("admin/admin-memberships.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n \n
    \n
    \n
    \n
    Member
    \n
    Admin
    \n
    Role
    \n
    Status
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    New Member

    \n
    \n Create\n

    If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation.

    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-default-values.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Project Profile

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n

    Default Values

    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n Save\n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-export.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Project Profile

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n

    Export your project to save a backup or to create a new one based on this.

    \n
    \n \n
    \n
    \"loading...\"/
    \n

    \n

    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-modules.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Project Profile

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
    \n
    \n
    \n

    Backlog Manage your user stories to maintain an organized view of upcoming and prioritized work.

    \n
    \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n

    Kanban Organize your project in a lean way with this board.

    \n
    \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n

    Issues Track the bugs, questions and enhancements related to your project. Don\'t miss anything!

    \n
    \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n

    Wiki Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.

    \n
    \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n

    Meet Up Choose your videoconference system. Even developers need face to face contact.

    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n
    \n
    \n Save\n
    \n
    "); +$templateCache.put("admin/admin-project-profile.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Project Profile

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n

    All projects are private during Taiga\'s beta period.

    \n
    \n SaveDelete this project\n
    \n
    \n
    \n
    \n
    \n

    Delete project

    \n

    Are you sure you want to delete this project?All project data US/Tasks/Issues/Sprints/WikiPages will be lost! :-(

    \n \n
    \n
    "); +$templateCache.put("admin/admin-project-values-issue-priorities.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the priority levels users can assign to issues

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-values-issue-severities.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the severity level users can select to classify issues

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-values-issue-status.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the column headers that you will use to classify Issues

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    Slug
    \n
    Is closed?
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    {{ value.slug }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-values-issue-types.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the categories users can select to classify issues

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-values-task-status.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the column headers that you will use to classify Tasks related to each User Stories

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    Slug
    \n
    Is closed?
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    {{ value.slug }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-project-values-us-points.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the numerical system you will use to indicate the level of difficulty for each User Story

    \n \n
    \n
    \n
    \n
    Name
    \n
    Value
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    {{ value.value }}
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    \n User Story (US) Points:\n

    \n

    Most people start off with 1 point = 1 man day of effort. If you\'re new to scrum & agile start there.

    \n

    \n After the first week if you and your team expected to accomplish 25 points (i.e. 5 people 5 full days)\n and only got half done, learn from your findings, and adjust expectations for the following week.\n By doing so you\'ll learn your teams true \'velocity.\'\n

    \n \n
    \n
    "); +$templateCache.put("admin/admin-project-values-us-status.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Custom Attributes

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Specify the column headers that you will use to classify User Stories

    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    Slug
    \n
    Is closed?
    \n
    Is archived?
    \n
    WIP Limit
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.name }}
    \n
    {{ value.slug }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    {{ value.wip_limit }}
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-roles.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Roles

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n
    \n
    \n \n
    \n

    {{ role.name }}

    \n
    \n
    Be careful, no role in your project will be able to estimate the point value for user stories
    \n
    When enabled, members assigned to this role will be able to estimate the point value for user stories\n
    \n \n
    YesNo\n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("admin/admin-third-parties-bitbucket.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Services

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    Copy to clipboard: Ctrl+C
    \n
    \n
    \n
    \n
    \n \n \n
    \n Save\n
    Do you need help? Check out our support page!\n
    \n
    "); +$templateCache.put("admin/admin-third-parties-github.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Services

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    Copy to clipboard: Ctrl+C
    \n
    \n
    \n
    \n Save\n
    Do you need help? Check out our support page!\n
    \n
    "); +$templateCache.put("admin/admin-third-parties-gitlab.html","\nTaiga Your agile, free, and open source project management tool\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Services

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n \n \n
    \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    Copy to clipboard: Ctrl+C
    \n
    \n
    \n
    \n
    \n \n \n
    \n Save\n
    Do you need help? Check out our support page!\n
    \n
    "); +$templateCache.put("admin/admin-third-parties-webhooks.html","\nTaiga Your agile, free, and open source project management tool\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Services

    \n
    \n \n
    \n
    \n
    \n
    \n

    \n
    \n

    Webhooks notify external services about events in Taiga, like comments, user stories....

    \n \n
    \n
    \n
    \n
    Name
    \n
    URL
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    Headers\n \n
    \n
    Payload\n \n
    \n
    \n
    Response
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    Do you need help? Check out our support page!\n
    \n
    "); +$templateCache.put("admin/memberships-row-avatar.html","\n
    \" alt=\"<%- full_name %>\"/>\n
    <%- full_name %><%- email %>
    \n
    "); +$templateCache.put("attachment/attachment-edit.html","\n\n
    <%- size %>
    \n
    \n \" placeholder=\"Type a short description\"/>\n
    \n
    \n -is-deprecated\"/>\n \n
    \n
    "); +$templateCache.put("attachment/attachment.html","\n\n
    <%- size %>
    \n
    <% if (isDeprecated){ %>(deprecated)<% } %><%- description %>
    <% if (modifyPermission) {%>\n
    <% } %>"); +$templateCache.put("attachment/attachments.html","\n
    \n
    \n

    attachments

    \n
    \" title=\"Add new attachment. <%- maxFileSizeMsg %>\" class=\"add-attach\"><% if (maxFileSize){ %>[Max. size: <%- maxFileSize %>]<% }; %>\n \n \n
    \n
    \n \n
    "); +$templateCache.put("auth/change-password-from-recovery.html","\n
    \n
    \n
    \n

    \"TAIGA\"

    \n

    Your agile, free, and open source project management tool

    \n
    \n

    Create a new Taiga pass
    And hey, you may want to eat some more iron-rich food, it\'s good for your brain :P

    \n
    \n
    \n Need one?\n
    \n
    \n \n
    \n
    \n \n
    \n
    Reset Password\n \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("auth/forgot-password.html","\n
    \n
    \n
    \"TAIGA\"\n

    Taiga

    \n

    LOVE YOUR PROJECT

    \n
    \n

    Oops, did you forget your password?
    Enter your username or email to get a new one

    \n
    \n
    \n \n
    \n
    \n Reset Password\n
    Nah, take me back. I think I remember it.\n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("auth/invitation.html","\n
    \n
    \n
    \n
    \n

    has invited you to join the project

    \n

    \n
    \n
    \n

    I already have a Taiga login

    \n
    \n \n
    \n
    \n Forgot it?\n
    \n
    Enter\n \n
    \n
    \n
    \n
    \n

    Register a new Taiga account (free)

    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n Sign up\n
    \n \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("auth/login-text.html","\n

    Not registered yet? create your free account here

    "); +$templateCache.put("auth/login.html","\n
    \n
    \n
    \"TAIGA\"\n

    Taiga

    \n

    LOVE YOUR PROJECT

    \n
    \n
    \n
    \n \n
    \n
    \n \n Forgot it?\n
    \n
    \n Sign in\n
    \n
    \n
    \n \n
    \n
    \n
    \n
    "); +$templateCache.put("auth/register.html","\n
    \n
    \n
    \"TAIGA\"\n

    Taiga

    \n

    LOVE YOUR PROJECT

    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n Sign up\n
    \n
    \n \n Are you already registered? Log in\n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("backlog/backlog.html","\n
    \n \n
    \n
    \n

    filters

    \n
    \n
    \n \n
    \n
    \n
    \n
    \n

    Filtersstatus

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
    \n
      \n
    • --project
      points
    • \n
    • --defined
      points
    • \n
    • --closed
      points
    • \n
    • --points /
      sprint
    • \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    User Storiess
    \n
    Status
    \n
    Points
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n \n
    \n \n
    \n
    \n

    SPRINTS

    \n
    \n
      \n
    • --
      sprints
    • \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    Sprint Taskboard\n
    Show closed sprints\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    Sprint Taskboard\n
    \n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n Create\n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n Save\n
    \n
    \n
    \n
    \n

    New Sprint

    \n
    \n \n \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n Create\n
    Do you want to delete this sprint?
    \n
    \n
    \n
    "); +$templateCache.put("backlog/filter-selected.html","<% _.each(filters, function(f) { %>\" data-id=\"<%- f.id %>\" class=\"single-filter selected\">\" class=\"name\"><%- f.name %><% }) %>"); +$templateCache.put("backlog/filters.html","\n<% _.each(filters, function(f) { %>\n<% if (f.selected) { %>\" data-id=\"<%- f.id %>\" class=\"single-filter active\">\" class=\"name\"><%- f.name %><%- f.count %><% } else { %>\" data-id=\"<%- f.id %>\" class=\"single-filter\">\" class=\"name\"><%- f.name %><%- f.count %><% } %>\n<% }) %>"); +$templateCache.put("backlog/progress-bar.html","\n
    \n
    %\" class=\"project-points-progress\">
    \n
    %\" class=\"closed-points-progress\">
    "); +$templateCache.put("backlog/sprint-header.html","\n
    <% if(isVisible){ %>\" title=\"\'Go to the taskboard of \'<%- name %>\'\"><%- name %><% } %>\n <% if(isEditable){ %><% } %>\n
    \n
    \n
    <%- estimatedDateRange %>
    \n
      \n
    • <%- closedPoints %>closed
    • \n
    • <%- totalPoints %>total
    • \n
    \n
    "); +$templateCache.put("backlog/us-points-popover.html","\n"); +$templateCache.put("backlog/us-points-roles-popover.html","\n"); +$templateCache.put("backlog/us-role-points-popover.html","\n"); +$templateCache.put("contrib/main.html","\nTaiga Your agile, free, and open source project management tool\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Contrib plugins

    \n
    \n \n
    \n
    \n
    \n
    "); +$templateCache.put("error/error.html","\n
    \n
    \n \"TAIGA\"/\n

    Taiga

    \n

    Something happened and our Oompa Loompas are working on it.
    Try reloading again soon.

    Take me home\n
    \n
    "); +$templateCache.put("error/not-found.html","\n
    \n
    \n \"TAIGA\"/\n

    Not found

    \n

    Error 404. The page you are looking for no longer exists. Perhaps you can return back to TAIGA homepage and see if you can find what you are looking for.

    Take me home\n
    \n
    "); +$templateCache.put("error/permission-denied.html","\n
    \n
    \n \"TAIGA\"/\n

    Permission denied

    \n

    Error 403.

    Take me home\n
    \n
    "); +$templateCache.put("issue/issue-paginator.html","\n
      <% if (showPrevious) { %>\n
    • Prev
    • <% } %>\n <% _.each(pages, function(item) { %>\n
    • \"><% if (item.type === \"page\") { %>\"><%- item.num %><% } else if (item.type === \"page-active\") { %><%- item.num %><% } else { %>...<% } %>
    • <% }); %>\n <% if (showNext) { %>\n
    • Next
    • <% } %>\n
    "); +$templateCache.put("issue/issue-priority-button.html","\n
    clickable<% }%>\">\" class=\"level\"><%- priority.name %><% if(editable){ %><% }%>priority\n \n
    "); +$templateCache.put("issue/issue-severity-button.html","\n
    clickable<% }%>\">\" class=\"level\"><%- severity.name %><% if(editable){ %><% }%>severity\n \n
    "); +$templateCache.put("issue/issue-status-inline-edition-selection.html","\n"); +$templateCache.put("issue/issue-type-button.html","\n
    clickable<% }%>\">\" class=\"level\"><%- type.name %><% if(editable){ %><% }%>type\n \n
    "); +$templateCache.put("issue/issues-detail.html","\n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
    \n

    \n \n

    This issue has been created from{{ issue.external_reference[1] }}

    \n

    Blocked

    \n
    \n
    \n
    \n
    \n
    \n \n \n
    \n \n
    \n

    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n \n \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("issue/issues-filters-selected.html","<% _.each(filters, function(f) { %>\" data-id=\"<%- f.id %>\" class=\"single-filter selected\">\" class=\"name\"><%- f.name %><% }) %>"); +$templateCache.put("issue/issues-filters.html","\n<% _.each(filters, function(f) { %>\n<% if (!f.selected) { %>\" data-id=\"<%- f.id %>\" class=\"single-filter\">\" class=\"name\"><%- f.name %><% if (f.count){ %><%- f.count %><% } %>\n <% if (f.type == \"myFilters\"){ %><% } %><% } %>\n<% }) %>\n"); +$templateCache.put("issue/issues-status-button.html","\n
    clickable<% }%>\">\" class=\"level\"><%- status.name %><% if(editable){ %><% } %>status\n \n
    "); +$templateCache.put("issue/issues-status-display.html","\n <% if (status.is_closed) { %>\n Closed\n <% } else { %>\n Open\n <% } %>\" class=\"us-detail-status\"><%- status.name %>"); +$templateCache.put("issue/issues.html","\n
    \n \n
    \n
    \n

    filters

    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
      \n \n \n \n \n \n \n \n \n
    \n \n
    \n
    \n
    \n
    Type
    \n
    Severity
    \n
    Priority
    \n
    Subject
    \n
    Status
    \n
    Created
    \n
    Assigned to
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    There are no issues to report :-)Did you find an issue?Create a new Issue
    \n \n
    \n
    \n
    \n
    \n
    \n

    Add Issue

    \n
    \n \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n
    \n \n Create\n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n Save\n
    \n
    \n
    "); +$templateCache.put("issue/promote-issue-to-us-button.html","Promote to User Story"); +$templateCache.put("kanban/kanban-task.html","\n
    \n
    \n
    \n
    \n

    pointsNot estimated

    \n
    \n
    \n

    You have archived

    \n

    \n

    Drag & drop again to undo

    \n
    \n
    "); +$templateCache.put("kanban/kanban.html","\n
    \n
    \n
    \n
    \n

    \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n

    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n Create\n
    \n
    \n
    \n
    \n

    \n
    \n \n
    \n Save\n
    \n
    \n
    \n
    "); +$templateCache.put("project/project-colors.html","\n
    \n \n
    \n
    \n

    Admin

    \n
    \n \n
    \n
    \n \n
    \n
    \n

    Roles

    \n
    \n \n
    \n
    \n
    \n
    \n
    \n

    \n
    \n
    \n \n
    \n
    \n
    \n
    Color
    \n
    Name
    \n
    Is closed?
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
      \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    • \n
    \n \n
    \n
    \n
    \n
    Ready for test
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    "); +$templateCache.put("project/project-list.html","\n
    \n
    \n
    \n \n
    \n
    \n
    "); +$templateCache.put("project/project-menu.html","\n
    \n
      \n
    • Search
    • <% if (project.is_backlog_activated && project.my_permissions.indexOf(\"view_us\") != -1) { %>\n
    • Backlog
    • <% } %>\n <% if (project.is_kanban_activated && project.my_permissions.indexOf(\"view_us\") != -1) { %>\n
    • Kanban
    • <% } %>\n <% if (project.is_issues_activated && project.my_permissions.indexOf(\"view_issues\") != -1) { %>\n
    • Issues
    • <% } %>\n <% if (project.is_wiki_activated && project.my_permissions.indexOf(\"view_wiki_pages\") != -1) { %>\n
    • Wiki
    • <% } %>\n
    • Team
    • <% if (project.videoconferences) { %>\n
    • Meet Up
    • <% } %>\n <% if (project.i_am_owner) { %>\n
    • Admin
    • <% } %>\n
    \n
    \n \n
    \n
    "); +$templateCache.put("project/project-navigation-base.html","\n

    Your projects

    \n
    \n
    \n \n
    \n
    \n
    \n project\n
    \n \n
    \n
    \n
    \n
    \n
      \n
      \n
      "); +$templateCache.put("project/project-navigation-list.html","<% _.each(projects, function(project) { %>\n
    • \"><%- project.name %>
    • <% }) %>"); +$templateCache.put("project/project.html","\n
      \n
      \n

      \n
      \n
        \n
      • project
        points
      • \n
      • defined
        points
      • \n
      • assigned
        points
      • \n
      • closed
        points
      • \n
      \n
      \n
      \n

      \n
        \n
      • \n
        \n
      • \n
      \n
      \n
      \n
      "); +$templateCache.put("project/projects.html","\n
      \n
      \n
      \n
      \n

      Welcome

      logout\n
      \n
      \n
      \n
      \n
      \n \n
      \n
      \n

      Projects

      \n
      \n
      Create project\n
      \n \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("search/search.html","\n
      \n \n
      \n
      \n
      \n \n
      \n
      \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n \n
      \n
      \n \n \n \n \n
      \n
      "); +$templateCache.put("task/related-task-create-form.html","\n
      \n
      \n \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("task/related-task-row-edit.html","\n
      \n
      \n sdfdsf\" placeholder=\"Type the task subject\"/>\n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("task/related-task-row.html","\n
      \n
      <%- task.subject %>\" class=\"clickable\">#<%- task.ref %><%- task.subject %>\n
      <% if(perms.modify_task) { %><% } %>\n <% if(perms.delete_task) { %><% } %>\n
      \n
      \n
      \n\n
      \n
      \n
      <% if(perms.modify_task) { %><% } %>\n
      \n
      "); +$templateCache.put("task/task-detail.html","\n
      \n
      \n
      \n
      \n

      \n
      \n \n
      \n
      \n
      \n

      \n \n

      This task has been created from{{ task.external_reference[1] }}

      \n

      Blocked

      \n
      \n
      \n
      \n
      \n
      \n \n \n
      \n \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n \n \n \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("taskboard/taskboard-user.html","\n
      \n
      "); +$templateCache.put("taskboard/taskboard.html","\n
      \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
        \n
      • total
        points
      • \n
      • completed
        points
      • \n
      \n
        \n
      • open
        tasks
      • \n
      • closed
        tasks
      • \n
      \n
        \n
      • iocaine
        doses
      • \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n

      \"User story\"

      \n

      \n
      \n
      \n
      \n
      \n
      \n
      \n

      \n

      points

      \n
      \n
      \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
      \n

      Unassigned tasks

      \n
      \n
      \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n

      \n
      \n \n
      \n
      \n \n
      \n
      \n \n
      \n
      \n
      \n
      \n
      \n \n
      \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n \n Create\n
      \n
      \n
      \n
      \n

      \n
      \n \n
      \n Save\n
      \n
      \n
      \n
      \n

      Select assigned to

      \n
      \n \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("team/leave-project.html","Leave this project"); +$templateCache.put("team/team-filter.html","\n"); +$templateCache.put("team/team-member-current-user.html","\n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("team/team-member-stats.html","\n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("team/team-members.html","\n
      \n
      \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("team/team.html","\n
      \n \n
      \n
      \n
      \n

      filters

      \n
      \n
      \n
      \n \n
      \n
      \n \n
      \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
      Mr. Wolf\n
      Closed issues
      \n
      \n
      Iocaine Drinker\n
      Iocaine doses ingested
      \n
      \n
      Cervantes\n
      Wiki pages edited
      \n
      \n
      \n Bug Hunter\n
      Bugs reported
      \n
      \n
      Night Shift\n
      Tasks closed
      \n
      \n
      \n Power\n
      Total Points
      \n
      \n
      \n
      \n
      \n
      \n

      Team > {{filtersRole.name || \"All\"}}

      \n
      \n
      \n
      "); +$templateCache.put("us/us-client-requirement-button.html","\n\n"); +$templateCache.put("us/us-detail.html","\n
      \n
      \n
      \n
      \n

      \n
      \n \n
      \n
      \n
      \n

      \n \n

      This US has been created from{{ us.external_reference[1] }}

      \n

      Blocked

      \n
      \n
      \n
      \n
      \n
      \n
      \n
      Related tasks\n
      \n
      \n
      \n
      \n
      \n
      \n
      \n \n \n
      \n \n
      \n

      \n
      \n \n \n
      \n
      \n
      \n
      \n
      \n
      \n
      \n \n \n \n \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("us/us-status-button.html","\n
      \" class=\"level\"><%- status.name %><% if(editable){ %><% }%>status\n \n
      "); +$templateCache.put("us/us-task-progress.html","\n
      %\" class=\"current-progress\"><%- totalClosedTasks %>/<%- totalTasks %> tasks completed
      "); +$templateCache.put("us/us-team-requirement-button.html","\n\n"); +$templateCache.put("user/cancel-account.html","\n
      \n
      \n
      \n

      \"TAIGA\"

      \n

      Your agile, free, and open source project management tool

      \n
      \n

      Cancel your account
      We\'re sorry you are leaving the taiga, we hope you enjoyed your stay :)

      \n
      \n
      \n Yes, I\'m leaving!\n \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("user/change-email.html","\n
      \n
      \n
      \n

      \"TAIGA\"

      \n

      Your agile, free, and open source project management tool

      \n
      \n

      Change your email
      One click more and your email will be updated!

      \n
      \n
      \n Change email\n \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("user/mail-notifications.html","\n
      \n \n
      \n
      \n

      User Settings

      \n
      \n \n
      \n
      \n
      \n
      \n

      \n
      \n

      Notifications By Mail

      \n
      \n
      \n
      \n
      Project
      \n
      Receive All
      \n
      Only Involved
      \n
      No notifications
      \n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("user/user-change-password.html","\n
      \n \n
      \n
      \n

      User Settings

      \n
      \n \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n Save\n
      \n
      \n
      \n
      "); +$templateCache.put("user/user-profile.html","\n
      \n \n
      \n
      \n

      User Settings

      \n
      \n \n
      \n
      \n
      \n
      \n

      \n
      \n
      \n
      \n
      \n
      \n
      \"avatar\"\n
      \n
      \n \n

      The image will be cropped to 80x80px.

      ChangeUse gravatar image\n
      \n
      \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n \n \n
      \n
      \n
      \n
      \n SaveDelete Taiga account\n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("wiki/editable-wiki-content.html","\n
      \n
      \n
      \n"); +$templateCache.put("wiki/wiki-nav.html","\n
      \n

      Links

      \n
      \n<% if (addWikiLinkPermission) { %>Add link<% } %>"); +$templateCache.put("wiki/wiki-summary.html","\n
        \n
      • <%- totalEditions %>times
        edited
      • \n
      • <%- lastModifiedDate %>last
        edit
      • \n
      • \n
        \" alt=\"<%- user.name %>\"/>
        last modification<%- user.name %>\n
      • \n
      "); +$templateCache.put("wiki/wiki.html","\n
      \n \n
      \n
      \n
      \n
      \n

      Wiki

      \n
      \n
      \n
      \n Remove this wiki page\n
      \n
      "); +$templateCache.put("common/components/assigned-to.html","<% if (assignedTo) { %>\n
      \" alt=\"<%- assignedTo.full_name_display %>\"/>
      <% } %>\n"); +$templateCache.put("common/components/block-button.html","BlockUnblock"); +$templateCache.put("common/components/created-by.html","\n
      \" alt=\"<%- owner.full_name_display %>\"/>
      \n
      Created by <%- owner.full_name_display %><%- date %>
      "); +$templateCache.put("common/components/delete-button.html","Delete"); +$templateCache.put("common/components/editable-description-msg-edit-mode.html","\n

      Empty space is so boring... go on be descriptive... A rose by any other name would smell as sweet...

      "); +$templateCache.put("common/components/editable-description-msg-read-mode.html","\n

      No description yet.

      "); +$templateCache.put("common/components/editable-description.html","\n
      \n
      \n
      \n"); +$templateCache.put("common/components/editable-subject.html","\n
      {{ item.subject }}
      \n
      \n \n
      "); +$templateCache.put("common/components/level.html","\n
      "); +$templateCache.put("common/components/list-item-assigned-to-avatar.html","\n
      \" alt=\"<%- name %>\"/>\n
      <%- name %>
      \n
      "); +$templateCache.put("common/components/main-title.html","<%- projectName %><%- sectionName %>"); +$templateCache.put("common/components/progress-bar.html","\n
      %\" class=\"current-progress\">
      "); +$templateCache.put("common/components/status-display.html","\n <% if (status.is_closed) { %>\n Closed\n <% } else { %>\n Open\n <% } %>\" class=\"us-detail-status\"><%- status.name %>"); +$templateCache.put("common/components/watchers.html","<% if(isEditable){ %>\n
      watchers
      <% } else if(watchers.length > 0){ %>\n
      watchers
      <% }; %>\n<% _.each(watchers, function(watcher) { %>\n<% if(watcher) { %>\n
      \n
      \" class=\"avatar\">\" alt=\"<%- watcher.full_name_display %>\"/>
      \n
      <%- watcher.full_name_display %><% if(isEditable){ %>\" href=\"\" title=\"delete-watcher\" class=\"icon icon-delete\"><% }; %>
      \n
      <% } %>\n<% }); %>"); +$templateCache.put("common/estimation/lb-us-estimation-points-per-role.html","\n
        \n
      • <%- totalPoints %>total
      • <% _.each(roles, function(role) { %>\n
      • \" class=\"total clickable\"><%- role.points %><%- role.name %>
      • <% }); %>\n
      "); +$templateCache.put("common/estimation/lb-us-estimation-points.html","\n"); +$templateCache.put("common/estimation/us-estimation-points-per-role.html","\n
        \n
      • <%- totalPoints %>total
      • <% _.each(roles, function(role) { %>\n
      • \" class=\"total <% if(editable){ %>clickable<% } %>\"><%- role.points %><%- role.name %>
      • <% }); %>\n
      "); +$templateCache.put("common/estimation/us-estimation-points.html","\n"); +$templateCache.put("common/history/history-activity.html","\n
      \">\n \n
      \n
      <%- userFullName %><%- creationDate %>
      <% if (comment.length > 0) { %>\n <% if ((deleteCommentDate || deleteCommentUser)) { %>\n
      Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>
      <% } %>\n
      \n <%= comment %>\n <% if (!deleteCommentDate && mode !== \"activity\" && canDeleteComment) { %>\" class=\"icon icon-delete comment-delete\"><% } %>\n
      <% } %>\n <% if(changes.length > 0) { %>\n
      <% if (mode != \"activity\") { %><%- changesText %><% } %>\n <% _.each(changes, function(change) { %>\n <%= change %>\n
      <% }) %>\n <% } %>\n
      \n
      "); +$templateCache.put("common/history/history-base-entries.html","<% if (showMore > 0) { %>+ Show previous entries (<%- showMore %> more)<% } %>\n<% _.each(entries, function(entry) { %>\n<%= entry %>\n<% }) %>"); +$templateCache.put("common/history/history-base.html","\n
      \n \n
      \n
      \n
      \" tg-toggle-comment=\"tg-toggle-comment\" class=\"add-comment\">\n <% if (mode !== \"edit\") { %>Markdown syntax helpComment<% } %>\n
      \n
      \n
      \n
      \n
      \n
      "); +$templateCache.put("common/history/history-change-attachment.html","\n
      \n
      <%- name %>
      \n
      <% _.each(diff, function(change) { %>\n

      <%- change.name %> from
      <%- change.from %>\n

      <%- change.name %> to
      <%- change.to %>

      \n

      <% }) %>\n
      \n
      "); +$templateCache.put("common/history/history-change-diff.html","\n
      \n
      <%- name %>
      \n
      \n

      <%= diff %>

      \n
      \n
      "); +$templateCache.put("common/history/history-change-generic.html","\n
      \n
      <%- name %>
      \n
      \n

      from
      <%- from %>

      \n

      to
      <%- to %>

      \n
      \n
      "); +$templateCache.put("common/history/history-change-points.html","<% _.each(points, function(point, name) { %>\n
      \n
      US points (<%- name.toLowerCase() %>)
      \n
      \n

      from
      <%- point[0] %>

      \n

      to
      <%- point[1] %>

      \n
      \n
      <% }); %>"); +$templateCache.put("common/history/history-deleted-comment.html","\n
      \n
      Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %>(Show deleted comment)(Hide deleted comment)\n
      <%= deleteComment %>
      \n
      <% if (canRestoreComment) { %>\" class=\"comment-restore\">Restore comment<% } %>\n
      "); +$templateCache.put("common/lightbox/lightbox-assigned-to-users.html","<% if (selected) { %>\n<% } %>\n<% _.each(users, function(user) { %>\n<% }) %>\n<% if (showMore) { %>\n
      ...too many users, keep filtering
      <% } %>"); +$templateCache.put("common/lightbox/lightbox-assigned-to.html","\n
      \n

      Select assigned to

      \n
      \n \n
      \n
      \n
      "); +$templateCache.put("common/lightbox/lightbox-block.html","\n
      \n

      \n
      \n \n
      Save\n
      "); +$templateCache.put("common/lightbox/lightbox-blocking-message-input.html","\n
      \n \n
      "); +$templateCache.put("common/lightbox/lightbox-users.html","\n
      \n

      Add watchers

      \n
      \n \n
      \n
      //- The content of this is rendered by directive
      \n
      "); +$templateCache.put("common/popover/popover-related-task-status.html","\n"); +$templateCache.put("common/popover/popover-us-status.html","\n"); +$templateCache.put("common/tag/lb-tag-line-tags.html","<% _.each(tags, function(tag) { %>\" class=\"tag\"><%- tag.name %><% }); %>"); +$templateCache.put("common/tag/lb-tag-line.html","\n
      \n"); +$templateCache.put("common/tag/tag-line.html","\n
      Add tag\n"); +$templateCache.put("common/tag/tags-line-tags.html","<% _.each(tags, function(tag) { %>;\" class=\"tag\"><%- tag.name %><% if (isEditable) { %><% } %><% }); %>"); +$templateCache.put("common/wysiwyg/wysiwyg-markitup-preview.html","\n
      \n
      \n
      <%= data %>
      \n
      \n
      "); +$templateCache.put("user/lightbox/lightbox-delete-account.html","\n
      \n

      Delete Taiga Account

      \n

      Are you sure you want to delete your Taiga account?We\'re going to miss you! :-(

      \n \n
      ");}]); \ No newline at end of file diff --git a/dist/partials/admin-memberships.html b/dist/partials/admin-memberships.html deleted file mode 100644 index 1779716..0000000 --- a/dist/partials/admin-memberships.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Member
      Admin
      Role
      Status
      \ No newline at end of file diff --git a/dist/partials/admin-project-default-values.html b/dist/partials/admin-project-default-values.html deleted file mode 100644 index e222422..0000000 --- a/dist/partials/admin-project-default-values.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Project Profile

      Default Values

      Save
      \ No newline at end of file diff --git a/dist/partials/admin-project-modules.html b/dist/partials/admin-project-modules.html deleted file mode 100644 index ee8ad18..0000000 --- a/dist/partials/admin-project-modules.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Project Profile

      Backlog Manage your user stories to maintain an organized view of upcoming and prioritized work.

      Kanban Organize your project in a lean way with this board.

      Issues Track the bugs, questions and enhancements related to your project. Don't miss anything!

      Wiki Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.

      Meet Up Choose your videoconference system. Even developers need face to face contact.

      Save
      \ No newline at end of file diff --git a/dist/partials/admin-project-profile.html b/dist/partials/admin-project-profile.html deleted file mode 100644 index c5274e3..0000000 --- a/dist/partials/admin-project-profile.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Project Profile

      All projects are private during Taiga's beta period.

      SaveDelete this project
      \ No newline at end of file diff --git a/dist/partials/admin-project-values-issue-priorities.html b/dist/partials/admin-project-values-issue-priorities.html deleted file mode 100644 index 8e1e064..0000000 --- a/dist/partials/admin-project-values-issue-priorities.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/admin-project-values-issue-severities.html b/dist/partials/admin-project-values-issue-severities.html deleted file mode 100644 index b54ef21..0000000 --- a/dist/partials/admin-project-values-issue-severities.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/admin-project-values-issue-status.html b/dist/partials/admin-project-values-issue-status.html deleted file mode 100644 index affbfc8..0000000 --- a/dist/partials/admin-project-values-issue-status.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Custom Attributes

      Specify the column headers that you will use to classify Issues

      Color
      Name
      Slug
      Is closed?
      {{ value.name }}
      {{ value.slug }}
      \ No newline at end of file diff --git a/dist/partials/admin-project-values-issue-types.html b/dist/partials/admin-project-values-issue-types.html deleted file mode 100644 index 8192f87..0000000 --- a/dist/partials/admin-project-values-issue-types.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/admin-project-values-task-status.html b/dist/partials/admin-project-values-task-status.html deleted file mode 100644 index 1bff7c7..0000000 --- a/dist/partials/admin-project-values-task-status.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Custom Attributes

      Specify the column headers that you will use to classify Tasks related to each User Stories

      Color
      Name
      Slug
      Is closed?
      {{ value.name }}
      {{ value.slug }}
      \ No newline at end of file diff --git a/dist/partials/admin-project-values-us-points.html b/dist/partials/admin-project-values-us-points.html deleted file mode 100644 index 7686b9f..0000000 --- a/dist/partials/admin-project-values-us-points.html +++ /dev/null @@ -1,3 +0,0 @@ -

      Admin

      Custom Attributes

      Specify the numerical system you will use to indicate the level of difficulty for each User Story

      Name
      Value
      {{ value.name }}
      {{ value.value }}
      \ No newline at end of file diff --git a/dist/partials/admin-project-values-us-status.html b/dist/partials/admin-project-values-us-status.html deleted file mode 100644 index e091371..0000000 --- a/dist/partials/admin-project-values-us-status.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Custom Attributes

      Specify the column headers that you will use to classify User Stories

      Color
      Name
      Slug
      Is closed?
      Is archived?
      WIP Limit
      {{ value.name }}
      {{ value.slug }}
      {{ value.wip_limit }}
      \ No newline at end of file diff --git a/dist/partials/admin-roles.html b/dist/partials/admin-roles.html deleted file mode 100644 index e99ae81..0000000 --- a/dist/partials/admin-roles.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      Roles

      {{ role.name }}

      Be careful, no role in your project will be able to estimate the point value for user stories
      When enabled, members assigned to this role will be able to estimate the point value for user stories
      YesNo
      \ No newline at end of file diff --git a/dist/partials/admin-third-parties-bitbucket.html b/dist/partials/admin-third-parties-bitbucket.html deleted file mode 100644 index 634d58d..0000000 --- a/dist/partials/admin-third-parties-bitbucket.html +++ /dev/null @@ -1 +0,0 @@ -Taiga Your agile, free, and open source project management tool \ No newline at end of file diff --git a/dist/partials/admin-third-parties-github.html b/dist/partials/admin-third-parties-github.html deleted file mode 100644 index 08d8700..0000000 --- a/dist/partials/admin-third-parties-github.html +++ /dev/null @@ -1 +0,0 @@ -Taiga Your agile, free, and open source project management tool \ No newline at end of file diff --git a/dist/partials/admin-third-parties-gitlab.html b/dist/partials/admin-third-parties-gitlab.html deleted file mode 100644 index 22c62f8..0000000 --- a/dist/partials/admin-third-parties-gitlab.html +++ /dev/null @@ -1 +0,0 @@ -Taiga Your agile, free, and open source project management tool \ No newline at end of file diff --git a/dist/partials/backlog.html b/dist/partials/backlog.html deleted file mode 100644 index 287d674..0000000 --- a/dist/partials/backlog.html +++ /dev/null @@ -1 +0,0 @@ -

      • --project
        points
      • --defined
        points
      • --closed
        points
      • --points /
        sprint
      User Stories
      Status
      Points

      SPRINTS

      • --
        sprints
      Show closed sprints
      \ No newline at end of file diff --git a/dist/partials/cancel-account.html b/dist/partials/cancel-account.html deleted file mode 100644 index 2a5a3c0..0000000 --- a/dist/partials/cancel-account.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/change-email.html b/dist/partials/change-email.html deleted file mode 100644 index 68131ca..0000000 --- a/dist/partials/change-email.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/change-password-from-recovery.html b/dist/partials/change-password-from-recovery.html deleted file mode 100644 index 1d49bea..0000000 --- a/dist/partials/change-password-from-recovery.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/contrib/main.html b/dist/partials/contrib/main.html deleted file mode 100644 index cc874dc..0000000 --- a/dist/partials/contrib/main.html +++ /dev/null @@ -1 +0,0 @@ -Taiga Your agile, free, and open source project management tool \ No newline at end of file diff --git a/dist/partials/dummy-layout.html b/dist/partials/dummy-layout.html deleted file mode 100644 index e69de29..0000000 diff --git a/dist/partials/error.html b/dist/partials/error.html deleted file mode 100644 index 6bcd61c..0000000 --- a/dist/partials/error.html +++ /dev/null @@ -1 +0,0 @@ -
      TAIGA

      Taiga

      Something happened and our Oompa Loompas are working on it.
      Try reloading again soon.

      Take me home
      \ No newline at end of file diff --git a/dist/partials/forgot-password.html b/dist/partials/forgot-password.html deleted file mode 100644 index b3ef80f..0000000 --- a/dist/partials/forgot-password.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/index.html b/dist/partials/index.html deleted file mode 100644 index e4c0e25..0000000 --- a/dist/partials/index.html +++ /dev/null @@ -1 +0,0 @@ -Taiga

      Loading project...

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description

      Everything is ok

      Our oompa Loompas saved all your changes!

      Oops, something happened...

      Our oompa Loompas are sad, your changes were not saved!

      Oops, something happened...

      Our oompa Loompas are sad, your changes were not saved!

      Loading...

      \ No newline at end of file diff --git a/dist/partials/invitation.html b/dist/partials/invitation.html deleted file mode 100644 index 4c8d725..0000000 --- a/dist/partials/invitation.html +++ /dev/null @@ -1 +0,0 @@ -

      has invited you to join the project

      Register a new Taiga account (free)

      Sign up
      \ No newline at end of file diff --git a/dist/partials/issues-detail.html b/dist/partials/issues-detail.html deleted file mode 100644 index 8a4ee89..0000000 --- a/dist/partials/issues-detail.html +++ /dev/null @@ -1 +0,0 @@ -

      This issue has been created from{{ issue.external_reference[1] }}

      Blocked

      \ No newline at end of file diff --git a/dist/partials/issues.html b/dist/partials/issues.html deleted file mode 100644 index 020350b..0000000 --- a/dist/partials/issues.html +++ /dev/null @@ -1 +0,0 @@ -

      Type
      Severity
      Priority
      Subject
      Status
      Created
      Assigned to
      There are no issues to report :-)Did you find an issue?Create a new Issue
      \ No newline at end of file diff --git a/dist/partials/kanban.html b/dist/partials/kanban.html deleted file mode 100644 index 833a5eb..0000000 --- a/dist/partials/kanban.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/layout.html b/dist/partials/layout.html deleted file mode 100644 index 81e2dfd..0000000 --- a/dist/partials/layout.html +++ /dev/null @@ -1 +0,0 @@ -

      Loading project...

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description
      \ No newline at end of file diff --git a/dist/partials/login-layout.html b/dist/partials/login-layout.html deleted file mode 100644 index baf7dbf..0000000 --- a/dist/partials/login-layout.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/login.html b/dist/partials/login.html deleted file mode 100644 index b541d89..0000000 --- a/dist/partials/login.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/mail-notifications.html b/dist/partials/mail-notifications.html deleted file mode 100644 index 38d054f..0000000 --- a/dist/partials/mail-notifications.html +++ /dev/null @@ -1 +0,0 @@ -

      User Settings

      Notifications By Mail

      Project
      Receive All
      Only Involved
      No notifications
      \ No newline at end of file diff --git a/dist/partials/not-found.html b/dist/partials/not-found.html deleted file mode 100644 index 92225da..0000000 --- a/dist/partials/not-found.html +++ /dev/null @@ -1 +0,0 @@ -
      TAIGA

      Not found

      Error 404. The page you are looking for no longer exists. Perhaps you can return back to TAIGA homepage and see if you can find what you are looking for.

      Take me home
      \ No newline at end of file diff --git a/dist/partials/permission-denied.html b/dist/partials/permission-denied.html deleted file mode 100644 index f25c1e0..0000000 --- a/dist/partials/permission-denied.html +++ /dev/null @@ -1 +0,0 @@ -
      TAIGA

      Permission denied

      Error 403.

      Take me home
      \ No newline at end of file diff --git a/dist/partials/project-colors.html b/dist/partials/project-colors.html deleted file mode 100644 index dd6ac2a..0000000 --- a/dist/partials/project-colors.html +++ /dev/null @@ -1 +0,0 @@ -Taiga Your agile, free, and open source project management tool

      Loading project...

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description

      Admin

      Roles

      Color
      Name
      Is closed?
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      \ No newline at end of file diff --git a/dist/partials/project.html b/dist/partials/project.html deleted file mode 100644 index 1da059a..0000000 --- a/dist/partials/project.html +++ /dev/null @@ -1 +0,0 @@ -

      • project
        points
      • defined
        points
      • assigned
        points
      • closed
        points

      \ No newline at end of file diff --git a/dist/partials/projects.html b/dist/partials/projects.html deleted file mode 100644 index 34d7f1d..0000000 --- a/dist/partials/projects.html +++ /dev/null @@ -1 +0,0 @@ -

      Welcome

      logout
      \ No newline at end of file diff --git a/dist/partials/register.html b/dist/partials/register.html deleted file mode 100644 index 165c7b0..0000000 --- a/dist/partials/register.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/search-issues.html b/dist/partials/search-issues.html deleted file mode 100644 index 63b8a83..0000000 --- a/dist/partials/search-issues.html +++ /dev/null @@ -1,7 +0,0 @@ -Taiga Your agile, free, and open source project management tool

      Loading project...

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description

      Issue
      Status
      Assigned to
      \ No newline at end of file diff --git a/dist/partials/search.html b/dist/partials/search.html deleted file mode 100644 index e1d72a1..0000000 --- a/dist/partials/search.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/task-detail.html b/dist/partials/task-detail.html deleted file mode 100644 index 42cacf1..0000000 --- a/dist/partials/task-detail.html +++ /dev/null @@ -1 +0,0 @@ -

      This task has been created from{{ task.external_reference[1] }}

      Blocked

      \ No newline at end of file diff --git a/dist/partials/taskboard.html b/dist/partials/taskboard.html deleted file mode 100644 index 07be8b2..0000000 --- a/dist/partials/taskboard.html +++ /dev/null @@ -1 +0,0 @@ -

      • total
        points
      • completed
        points
      • open
        tasks
      • closed
        tasks
      • iocaine
        doses

      "User story"

      points

      Unassigned tasks

      \ No newline at end of file diff --git a/dist/partials/us-detail.html b/dist/partials/us-detail.html deleted file mode 100644 index b81a85f..0000000 --- a/dist/partials/us-detail.html +++ /dev/null @@ -1 +0,0 @@ -

      This US has been created from{{ us.external_reference[1] }}

      Blocked

      \ No newline at end of file diff --git a/dist/partials/user-change-password.html b/dist/partials/user-change-password.html deleted file mode 100644 index 3eef447..0000000 --- a/dist/partials/user-change-password.html +++ /dev/null @@ -1 +0,0 @@ -

      User Settings

      Save
      \ No newline at end of file diff --git a/dist/partials/user-profile.html b/dist/partials/user-profile.html deleted file mode 100644 index 8712cb8..0000000 --- a/dist/partials/user-profile.html +++ /dev/null @@ -1 +0,0 @@ -

      User Settings

      \ No newline at end of file diff --git a/dist/partials/views/components/addnewtask.html b/dist/partials/views/components/addnewtask.html deleted file mode 100644 index 808734b..0000000 --- a/dist/partials/views/components/addnewtask.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/components/addnewus.html b/dist/partials/views/components/addnewus.html deleted file mode 100644 index d17eba8..0000000 --- a/dist/partials/views/components/addnewus.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/components/backlog-row.html b/dist/partials/views/components/backlog-row.html deleted file mode 100644 index 0e8e1dd..0000000 --- a/dist/partials/views/components/backlog-row.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/components/beta.html b/dist/partials/views/components/beta.html deleted file mode 100644 index 3532125..0000000 --- a/dist/partials/views/components/beta.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/components/filter.html b/dist/partials/views/components/filter.html deleted file mode 100644 index 9d178bc..0000000 --- a/dist/partials/views/components/filter.html +++ /dev/null @@ -1 +0,0 @@ -filter23 \ No newline at end of file diff --git a/dist/partials/views/components/help-notion-button.html b/dist/partials/views/components/help-notion-button.html deleted file mode 100644 index 6455054..0000000 --- a/dist/partials/views/components/help-notion-button.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/components/kanban-task.html b/dist/partials/views/components/kanban-task.html deleted file mode 100644 index 7958ec9..0000000 --- a/dist/partials/views/components/kanban-task.html +++ /dev/null @@ -1 +0,0 @@ -

      pointsNot estimated

      You have archived

      Drag & drop again to undo

      \ No newline at end of file diff --git a/dist/partials/views/components/large-summary.html b/dist/partials/views/components/large-summary.html deleted file mode 100644 index 598ae04..0000000 --- a/dist/partials/views/components/large-summary.html +++ /dev/null @@ -1 +0,0 @@ -
      30%completed
      • 12project
        points
      • 23defined
        points
      • 12assigned
        points
      • 23closed
        points
      • 73created
        tasks
      • 72closed
        tasks
      • 18remaining
        tasks
      • 10iocanie
        doses
      \ No newline at end of file diff --git a/dist/partials/views/components/loading-bar.html b/dist/partials/views/components/loading-bar.html deleted file mode 100644 index bc43ae8..0000000 --- a/dist/partials/views/components/loading-bar.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/components/mainTitle.html b/dist/partials/views/components/mainTitle.html deleted file mode 100644 index a426146..0000000 --- a/dist/partials/views/components/mainTitle.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/components/notification-message.html b/dist/partials/views/components/notification-message.html deleted file mode 100644 index 45ebbd9..0000000 --- a/dist/partials/views/components/notification-message.html +++ /dev/null @@ -1 +0,0 @@ -

      Everything is ok

      Our oompa Loompas saved all your changes!

      Oops, something happened...

      Our oompa Loompas are sad, your changes were not saved!

      Oops, something happened...

      Our oompa Loompas are sad, your changes were not saved!

      \ No newline at end of file diff --git a/dist/partials/views/components/select-color.html b/dist/partials/views/components/select-color.html deleted file mode 100644 index 74dfe6b..0000000 --- a/dist/partials/views/components/select-color.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/components/sprint-summary.html b/dist/partials/views/components/sprint-summary.html deleted file mode 100644 index 9dc716b..0000000 --- a/dist/partials/views/components/sprint-summary.html +++ /dev/null @@ -1 +0,0 @@ -
      • total
        points
      • completed
        points
      • open
        tasks
      • closed
        tasks
      • iocaine
        doses
      \ No newline at end of file diff --git a/dist/partials/views/components/summary.html b/dist/partials/views/components/summary.html deleted file mode 100644 index 9cfc11c..0000000 --- a/dist/partials/views/components/summary.html +++ /dev/null @@ -1 +0,0 @@ -
      • --project
        points
      • --defined
        points
      • --closed
        points
      • --points /
        sprint
      \ No newline at end of file diff --git a/dist/partials/views/components/taskboard-task.html b/dist/partials/views/components/taskboard-task.html deleted file mode 100644 index 300a0e5..0000000 --- a/dist/partials/views/components/taskboard-task.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/components/watchers.html b/dist/partials/views/components/watchers.html deleted file mode 100644 index 30e7832..0000000 --- a/dist/partials/views/components/watchers.html +++ /dev/null @@ -1 +0,0 @@ -
      watchers
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-menu.html b/dist/partials/views/modules/admin-menu.html deleted file mode 100644 index cef656e..0000000 --- a/dist/partials/views/modules/admin-menu.html +++ /dev/null @@ -1 +0,0 @@ -

      Admin

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu-contrib.html b/dist/partials/views/modules/admin-submenu-contrib.html deleted file mode 100644 index aa0dd8e..0000000 --- a/dist/partials/views/modules/admin-submenu-contrib.html +++ /dev/null @@ -1 +0,0 @@ -

      Contrib plugins

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu-project-profile.html b/dist/partials/views/modules/admin-submenu-project-profile.html deleted file mode 100644 index db321b6..0000000 --- a/dist/partials/views/modules/admin-submenu-project-profile.html +++ /dev/null @@ -1 +0,0 @@ -

      Project Profile

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu-project-values.html b/dist/partials/views/modules/admin-submenu-project-values.html deleted file mode 100644 index 5d572c8..0000000 --- a/dist/partials/views/modules/admin-submenu-project-values.html +++ /dev/null @@ -1 +0,0 @@ -

      Custom Attributes

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu-roles.html b/dist/partials/views/modules/admin-submenu-roles.html deleted file mode 100644 index 36d19f3..0000000 --- a/dist/partials/views/modules/admin-submenu-roles.html +++ /dev/null @@ -1 +0,0 @@ -

      Roles

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu-third-parties.html b/dist/partials/views/modules/admin-submenu-third-parties.html deleted file mode 100644 index 74b2b8c..0000000 --- a/dist/partials/views/modules/admin-submenu-third-parties.html +++ /dev/null @@ -1 +0,0 @@ -

      Third parties

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin-submenu.html b/dist/partials/views/modules/admin-submenu.html deleted file mode 100644 index 609769a..0000000 --- a/dist/partials/views/modules/admin-submenu.html +++ /dev/null @@ -1 +0,0 @@ -

      Roles

      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/admin-membership-table.html b/dist/partials/views/modules/admin/admin-membership-table.html deleted file mode 100644 index 13854dc..0000000 --- a/dist/partials/views/modules/admin/admin-membership-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Member
      Admin
      Role
      Status
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/default-values.html b/dist/partials/views/modules/admin/default-values.html deleted file mode 100644 index b08386b..0000000 --- a/dist/partials/views/modules/admin/default-values.html +++ /dev/null @@ -1 +0,0 @@ -
      Save
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/project-points.html b/dist/partials/views/modules/admin/project-points.html deleted file mode 100644 index 63a64f9..0000000 --- a/dist/partials/views/modules/admin/project-points.html +++ /dev/null @@ -1 +0,0 @@ -
      Name
      Value
      {{ value.name }}
      {{ value.value }}
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/project-status.html b/dist/partials/views/modules/admin/project-status.html deleted file mode 100644 index 771d33b..0000000 --- a/dist/partials/views/modules/admin/project-status.html +++ /dev/null @@ -1 +0,0 @@ -
      Color
      Name
      Slug
      Is closed?
      {{ value.name }}
      {{ value.slug }}
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/project-types.html b/dist/partials/views/modules/admin/project-types.html deleted file mode 100644 index b30f985..0000000 --- a/dist/partials/views/modules/admin/project-types.html +++ /dev/null @@ -1 +0,0 @@ -
      Color
      Name
      {{ value.name }}
      \ No newline at end of file diff --git a/dist/partials/views/modules/admin/project-us-status.html b/dist/partials/views/modules/admin/project-us-status.html deleted file mode 100644 index fb2201c..0000000 --- a/dist/partials/views/modules/admin/project-us-status.html +++ /dev/null @@ -1 +0,0 @@ -
      Color
      Name
      Slug
      Is closed?
      Is archived?
      WIP Limit
      {{ value.name }}
      {{ value.slug }}
      {{ value.wip_limit }}
      \ No newline at end of file diff --git a/dist/partials/views/modules/backlog-filters.html b/dist/partials/views/modules/backlog-filters.html deleted file mode 100644 index b47c74e..0000000 --- a/dist/partials/views/modules/backlog-filters.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/backlog-table.html b/dist/partials/views/modules/backlog-table.html deleted file mode 100644 index a1cfd35..0000000 --- a/dist/partials/views/modules/backlog-table.html +++ /dev/null @@ -1 +0,0 @@ -
      User Stories
      Status
      Points
      \ No newline at end of file diff --git a/dist/partials/views/modules/burndown.html b/dist/partials/views/modules/burndown.html deleted file mode 100644 index c672aa7..0000000 --- a/dist/partials/views/modules/burndown.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/cancel-account-form.html b/dist/partials/views/modules/cancel-account-form.html deleted file mode 100644 index 4aea04a..0000000 --- a/dist/partials/views/modules/cancel-account-form.html +++ /dev/null @@ -1 +0,0 @@ -

      Cancel your account
      We're sorry you are leaving the taiga, we hope you enjoyed your stay :)

      \ No newline at end of file diff --git a/dist/partials/views/modules/category-config.html b/dist/partials/views/modules/category-config.html deleted file mode 100644 index c214910..0000000 --- a/dist/partials/views/modules/category-config.html +++ /dev/null @@ -1 +0,0 @@ -
      Can do estimations?
      Attachments
      2/7
      User stories
      2/7
      Issues
      2/7
      Can modify owned user stories
      Can delete user story status
      Can delete user story status
      Can delete user story statsu
      Can delete user story status
      User stories
      2/7
      \ No newline at end of file diff --git a/dist/partials/views/modules/change-email-form.html b/dist/partials/views/modules/change-email-form.html deleted file mode 100644 index b738747..0000000 --- a/dist/partials/views/modules/change-email-form.html +++ /dev/null @@ -1 +0,0 @@ -

      Change your email
      One click more and your email will be updated!

      Change email
      \ No newline at end of file diff --git a/dist/partials/views/modules/change-password-from-recovery-form.html b/dist/partials/views/modules/change-password-from-recovery-form.html deleted file mode 100644 index 436e720..0000000 --- a/dist/partials/views/modules/change-password-from-recovery-form.html +++ /dev/null @@ -1 +0,0 @@ -

      Create a new Taiga pass
      And hey, you may want to eat some more iron-rich food, it's good for your brain :P

      Need one?
      Reset Password
      \ No newline at end of file diff --git a/dist/partials/views/modules/colors-table.html b/dist/partials/views/modules/colors-table.html deleted file mode 100644 index 7159f74..0000000 --- a/dist/partials/views/modules/colors-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Color
      Name
      Is closed?
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      Ready for test
      \ No newline at end of file diff --git a/dist/partials/views/modules/comment-activity.html b/dist/partials/views/modules/comment-activity.html deleted file mode 100644 index ca27014..0000000 --- a/dist/partials/views/modules/comment-activity.html +++ /dev/null @@ -1 +0,0 @@ -

      from

      to

      \ No newline at end of file diff --git a/dist/partials/views/modules/filter-tags.html b/dist/partials/views/modules/filter-tags.html deleted file mode 100644 index 73d6205..0000000 --- a/dist/partials/views/modules/filter-tags.html +++ /dev/null @@ -1 +0,0 @@ -
      Tagname
      4
      Tagname
      4
      Tagname
      4
      \ No newline at end of file diff --git a/dist/partials/views/modules/filters.html b/dist/partials/views/modules/filters.html deleted file mode 100644 index 59894df..0000000 --- a/dist/partials/views/modules/filters.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/forgot-form.html b/dist/partials/views/modules/forgot-form.html deleted file mode 100644 index 249289c..0000000 --- a/dist/partials/views/modules/forgot-form.html +++ /dev/null @@ -1 +0,0 @@ -

      Oops, did you forget your password?
      Enter your username or email to get a new one

      Reset Password
      Nah, take me back. I think I remember it.
      \ No newline at end of file diff --git a/dist/partials/views/modules/help-notions/lightbox-generic-notion.html b/dist/partials/views/modules/help-notions/lightbox-generic-notion.html deleted file mode 100644 index 699148e..0000000 --- a/dist/partials/views/modules/help-notions/lightbox-generic-notion.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/help-notions/lightbox-notion-admin-project-values-us-points.html b/dist/partials/views/modules/help-notions/lightbox-notion-admin-project-values-us-points.html deleted file mode 100644 index de2d21a..0000000 --- a/dist/partials/views/modules/help-notions/lightbox-notion-admin-project-values-us-points.html +++ /dev/null @@ -1,3 +0,0 @@ -

      User Story (US) Points:

      Most people start off with 1 point = 1 man day of effort. If you're new to scrum & agile start there.

      After the first week if you and your team expected to accomplish 25 points (i.e. 5 people 5 full days) -and only got half done, learn from your findings, and adjust expectations for the following week. -By doing so you'll learn your teams true 'velocity.'

      \ No newline at end of file diff --git a/dist/partials/views/modules/invitation-login-form.html b/dist/partials/views/modules/invitation-login-form.html deleted file mode 100644 index a247ad6..0000000 --- a/dist/partials/views/modules/invitation-login-form.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/invitation-register-form.html b/dist/partials/views/modules/invitation-register-form.html deleted file mode 100644 index 10ffecc..0000000 --- a/dist/partials/views/modules/invitation-register-form.html +++ /dev/null @@ -1 +0,0 @@ -

      Register a new Taiga account (free)

      Sign up
      \ No newline at end of file diff --git a/dist/partials/views/modules/issues-filters.html b/dist/partials/views/modules/issues-filters.html deleted file mode 100644 index 94303dc..0000000 --- a/dist/partials/views/modules/issues-filters.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/issues-table.html b/dist/partials/views/modules/issues-table.html deleted file mode 100644 index 555bd97..0000000 --- a/dist/partials/views/modules/issues-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Type
      Severity
      Priority
      Subject
      Status
      Created
      Assigned to
      There are no issues to report :-)Did you find an issue?Create a new Issue
      \ No newline at end of file diff --git a/dist/partials/views/modules/kanban-table.html b/dist/partials/views/modules/kanban-table.html deleted file mode 100644 index 16ef2ce..0000000 --- a/dist/partials/views/modules/kanban-table.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-add-member.html b/dist/partials/views/modules/lightbox-add-member.html deleted file mode 100644 index 3496b67..0000000 --- a/dist/partials/views/modules/lightbox-add-member.html +++ /dev/null @@ -1 +0,0 @@ -

      New Member

      Create

      If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation.

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-ask-choice.html b/dist/partials/views/modules/lightbox-ask-choice.html deleted file mode 100644 index 696df5c..0000000 --- a/dist/partials/views/modules/lightbox-ask-choice.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-assigned-to.html b/dist/partials/views/modules/lightbox-assigned-to.html deleted file mode 100644 index 751dfdd..0000000 --- a/dist/partials/views/modules/lightbox-assigned-to.html +++ /dev/null @@ -1 +0,0 @@ -

      Select assigned to

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-attachments.html b/dist/partials/views/modules/lightbox-attachments.html deleted file mode 100644 index e6d8c31..0000000 --- a/dist/partials/views/modules/lightbox-attachments.html +++ /dev/null @@ -1 +0,0 @@ -

      1attachment+ add attachment

      Comentario sobre el contenido(125kb.)
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-block.html b/dist/partials/views/modules/lightbox-block.html deleted file mode 100644 index db0f0cc..0000000 --- a/dist/partials/views/modules/lightbox-block.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-create-issue.html b/dist/partials/views/modules/lightbox-create-issue.html deleted file mode 100644 index 6193744..0000000 --- a/dist/partials/views/modules/lightbox-create-issue.html +++ /dev/null @@ -1 +0,0 @@ -

      Add Issue

      Create
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-delete-account.html b/dist/partials/views/modules/lightbox-delete-account.html deleted file mode 100644 index a0831c4..0000000 --- a/dist/partials/views/modules/lightbox-delete-account.html +++ /dev/null @@ -1 +0,0 @@ -

      Delete Taiga Account

      Are you sure you want to delete your Taiga account?We're going to miss you! :-(

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-delete-project.html b/dist/partials/views/modules/lightbox-delete-project.html deleted file mode 100644 index 8564678..0000000 --- a/dist/partials/views/modules/lightbox-delete-project.html +++ /dev/null @@ -1 +0,0 @@ -

      Delete project

      Are you sure you want to delete this project?All project data US/Tasks/Issues/Sprints/WikiPages will be lost! :-(

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-feedback.html b/dist/partials/views/modules/lightbox-feedback.html deleted file mode 100644 index 98ebba0..0000000 --- a/dist/partials/views/modules/lightbox-feedback.html +++ /dev/null @@ -1 +0,0 @@ -

      Tell us something...

      Send feedback
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-generic-ask.html b/dist/partials/views/modules/lightbox-generic-ask.html deleted file mode 100644 index 15ba9cf..0000000 --- a/dist/partials/views/modules/lightbox-generic-ask.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-generic-error.html b/dist/partials/views/modules/lightbox-generic-error.html deleted file mode 100644 index 699148e..0000000 --- a/dist/partials/views/modules/lightbox-generic-error.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-generic-success.html b/dist/partials/views/modules/lightbox-generic-success.html deleted file mode 100644 index 699148e..0000000 --- a/dist/partials/views/modules/lightbox-generic-success.html +++ /dev/null @@ -1 +0,0 @@ -

      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-issue-bulk.html b/dist/partials/views/modules/lightbox-issue-bulk.html deleted file mode 100644 index ccb2cac..0000000 --- a/dist/partials/views/modules/lightbox-issue-bulk.html +++ /dev/null @@ -1 +0,0 @@ -

      Save
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-search.html b/dist/partials/views/modules/lightbox-search.html deleted file mode 100644 index 4d4325e..0000000 --- a/dist/partials/views/modules/lightbox-search.html +++ /dev/null @@ -1 +0,0 @@ -

      Search

      Search
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-sprint-add-edit.html b/dist/partials/views/modules/lightbox-sprint-add-edit.html deleted file mode 100644 index 5f87535..0000000 --- a/dist/partials/views/modules/lightbox-sprint-add-edit.html +++ /dev/null @@ -1 +0,0 @@ -

      New Sprint

      Create
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-task-bulk.html b/dist/partials/views/modules/lightbox-task-bulk.html deleted file mode 100644 index 442aa61..0000000 --- a/dist/partials/views/modules/lightbox-task-bulk.html +++ /dev/null @@ -1 +0,0 @@ -

      Save
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-task-create-edit.html b/dist/partials/views/modules/lightbox-task-create-edit.html deleted file mode 100644 index c94acd1..0000000 --- a/dist/partials/views/modules/lightbox-task-create-edit.html +++ /dev/null @@ -1 +0,0 @@ -

      Create
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-us-bulk.html b/dist/partials/views/modules/lightbox-us-bulk.html deleted file mode 100644 index ccb2cac..0000000 --- a/dist/partials/views/modules/lightbox-us-bulk.html +++ /dev/null @@ -1 +0,0 @@ -

      Save
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-us-create-edit.html b/dist/partials/views/modules/lightbox-us-create-edit.html deleted file mode 100644 index cbb2313..0000000 --- a/dist/partials/views/modules/lightbox-us-create-edit.html +++ /dev/null @@ -1 +0,0 @@ -

      Create
      \ No newline at end of file diff --git a/dist/partials/views/modules/lightbox-users.html b/dist/partials/views/modules/lightbox-users.html deleted file mode 100644 index 87d634d..0000000 --- a/dist/partials/views/modules/lightbox-users.html +++ /dev/null @@ -1 +0,0 @@ -

      Add watchers

      //- The content of this is rendered by directive
      \ No newline at end of file diff --git a/dist/partials/views/modules/list-filters-kanban.html b/dist/partials/views/modules/list-filters-kanban.html deleted file mode 100644 index e483c0e..0000000 --- a/dist/partials/views/modules/list-filters-kanban.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/list-filters.html b/dist/partials/views/modules/list-filters.html deleted file mode 100644 index 3ef4a56..0000000 --- a/dist/partials/views/modules/list-filters.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/loader.html b/dist/partials/views/modules/loader.html deleted file mode 100644 index 1d47328..0000000 --- a/dist/partials/views/modules/loader.html +++ /dev/null @@ -1 +0,0 @@ -

      Loading...

      \ No newline at end of file diff --git a/dist/partials/views/modules/login-form.html b/dist/partials/views/modules/login-form.html deleted file mode 100644 index 1e2a867..0000000 --- a/dist/partials/views/modules/login-form.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/nav.html b/dist/partials/views/modules/nav.html deleted file mode 100644 index 277c40f..0000000 --- a/dist/partials/views/modules/nav.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/projects-nav.html b/dist/partials/views/modules/projects-nav.html deleted file mode 100644 index dc171af..0000000 --- a/dist/partials/views/modules/projects-nav.html +++ /dev/null @@ -1 +0,0 @@ -

      Loading project...

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description
      \ No newline at end of file diff --git a/dist/partials/views/modules/register-form.html b/dist/partials/views/modules/register-form.html deleted file mode 100644 index b2153f8..0000000 --- a/dist/partials/views/modules/register-form.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/related-tasks.html b/dist/partials/views/modules/related-tasks.html deleted file mode 100644 index d93d81f..0000000 --- a/dist/partials/views/modules/related-tasks.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/partials/views/modules/search-filter.html b/dist/partials/views/modules/search-filter.html deleted file mode 100644 index 399c9fe..0000000 --- a/dist/partials/views/modules/search-filter.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/search-in.html b/dist/partials/views/modules/search-in.html deleted file mode 100644 index b4add5b..0000000 --- a/dist/partials/views/modules/search-in.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/search-result-issues-table.html b/dist/partials/views/modules/search-result-issues-table.html deleted file mode 100644 index 1070c9f..0000000 --- a/dist/partials/views/modules/search-result-issues-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Issue
      Status
      Assigned to
      \ No newline at end of file diff --git a/dist/partials/views/modules/search-result-table.html b/dist/partials/views/modules/search-result-table.html deleted file mode 100644 index 73a2c48..0000000 --- a/dist/partials/views/modules/search-result-table.html +++ /dev/null @@ -1 +0,0 @@ -
      \ No newline at end of file diff --git a/dist/partials/views/modules/sprint.html b/dist/partials/views/modules/sprint.html deleted file mode 100644 index 10783e6..0000000 --- a/dist/partials/views/modules/sprint.html +++ /dev/null @@ -1 +0,0 @@ -
      Sprint Taskboard \ No newline at end of file diff --git a/dist/partials/views/modules/sprints.html b/dist/partials/views/modules/sprints.html deleted file mode 100644 index 7d432b6..0000000 --- a/dist/partials/views/modules/sprints.html +++ /dev/null @@ -1 +0,0 @@ -

      SPRINTS

      • --
        sprints
      Show closed sprints
      \ No newline at end of file diff --git a/dist/partials/views/modules/taskboard-table.html b/dist/partials/views/modules/taskboard-table.html deleted file mode 100644 index 899a904..0000000 --- a/dist/partials/views/modules/taskboard-table.html +++ /dev/null @@ -1 +0,0 @@ -

      "User story"

      points

      Unassigned tasks

      \ No newline at end of file diff --git a/dist/partials/views/modules/team/team-filters.html b/dist/partials/views/modules/team/team-filters.html deleted file mode 100644 index 81634d7..0000000 --- a/dist/partials/views/modules/team/team-filters.html +++ /dev/null @@ -1 +0,0 @@ -

      filters

      \ No newline at end of file diff --git a/dist/partials/views/modules/team/team-table.html b/dist/partials/views/modules/team/team-table.html deleted file mode 100644 index 86b9eba..0000000 --- a/dist/partials/views/modules/team/team-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Mr. Wolf
      Closed issues
      Iocaine Drinker
      Iocaine doses ingested
      Cervantes
      Wiki pages edited
      Bug Hunter
      Bugs reported
      Night Shift
      Tasks closed
      Power
      Total Points

      Team > {{filtersRole.name || "All"}}

      \ No newline at end of file diff --git a/dist/partials/views/modules/user-settings-menu.html b/dist/partials/views/modules/user-settings-menu.html deleted file mode 100644 index fc24fd2..0000000 --- a/dist/partials/views/modules/user-settings-menu.html +++ /dev/null @@ -1 +0,0 @@ -

      User Settings

      \ No newline at end of file diff --git a/dist/partials/views/modules/user-settings/mail-notifications-table.html b/dist/partials/views/modules/user-settings/mail-notifications-table.html deleted file mode 100644 index 243948f..0000000 --- a/dist/partials/views/modules/user-settings/mail-notifications-table.html +++ /dev/null @@ -1 +0,0 @@ -
      Project
      Receive All
      Only Involved
      No notifications
      \ No newline at end of file diff --git a/dist/partials/views/modules/wiki-nav.html b/dist/partials/views/modules/wiki-nav.html deleted file mode 100644 index e69de29..0000000 diff --git a/dist/partials/views/modules/wizard-create-project.html b/dist/partials/views/modules/wizard-create-project.html deleted file mode 100644 index 4d0dd52..0000000 --- a/dist/partials/views/modules/wizard-create-project.html +++ /dev/null @@ -1 +0,0 @@ -

      Choose a template

      Which template would fit better in your project?

      {{ template.description }}

      Next

      Create Project

      Fresh and clean. So exciting!

      Template selectionName and description
      \ No newline at end of file diff --git a/dist/partials/views/team/team.html b/dist/partials/views/team/team.html deleted file mode 100644 index 33e8d27..0000000 --- a/dist/partials/views/team/team.html +++ /dev/null @@ -1 +0,0 @@ -

      filters

      Mr. Wolf
      Closed issues
      Iocaine Drinker
      Iocaine doses ingested
      Cervantes
      Wiki pages edited
      Bug Hunter
      Bugs reported
      Night Shift
      Tasks closed
      Power
      Total Points

      Team > {{filtersRole.name || "All"}}

      \ No newline at end of file diff --git a/dist/partials/wiki.html b/dist/partials/wiki.html deleted file mode 100644 index 36db429..0000000 --- a/dist/partials/wiki.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/dist/styles/main.css b/dist/styles/main.css index 9846721..a664fe6 100644 --- a/dist/styles/main.css +++ b/dist/styles/main.css @@ -1,4 +1,4 @@ @charset "UTF-8";.mCustomScrollbar{-ms-touch-action:none;touch-action:none}.mCustomScrollbar.mCS_no_scrollbar{-ms-touch-action:auto;touch-action:auto}.mCustomScrollBox{position:relative;overflow:hidden;height:100%;max-width:100%;outline:0;direction:ltr}.mCSB_container{overflow:hidden;width:auto;height:auto}.mCSB_inside>.mCSB_container{margin-right:30px}.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{margin-right:0}.mCS-dir-rtl>.mCSB_inside>.mCSB_container{margin-right:0;margin-left:30px}.mCS-dir-rtl>.mCSB_inside>.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{margin-left:0}.mCSB_scrollTools{position:absolute;width:16px;height:auto;left:auto;top:0;right:0;bottom:0}.mCSB_outside+.mCSB_scrollTools{right:-26px}.mCS-dir-rtl>.mCSB_inside>.mCSB_scrollTools,.mCS-dir-rtl>.mCSB_outside+.mCSB_scrollTools{right:auto;left:0}.mCS-dir-rtl>.mCSB_outside+.mCSB_scrollTools{left:-26px}.mCSB_scrollTools .mCSB_draggerContainer{position:absolute;top:0;left:0;bottom:0;right:0;height:auto}.mCSB_scrollTools a+.mCSB_draggerContainer{margin:20px 0}.mCSB_scrollTools .mCSB_draggerRail{width:2px;height:100%;margin:0 auto;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px}.mCSB_scrollTools .mCSB_dragger{cursor:pointer;width:100%;height:30px;z-index:1}.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{position:relative;width:4px;height:100%;margin:0 auto;-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px;text-align:center}.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{width:12px}.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:8px}.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonUp{display:block;position:absolute;height:20px;width:100%;overflow:hidden;margin:0 auto;cursor:pointer}.mCSB_scrollTools .mCSB_buttonDown{bottom:0}.mCSB_horizontal.mCSB_inside>.mCSB_container{margin-right:0;margin-bottom:30px}.mCSB_horizontal.mCSB_outside>.mCSB_container{min-height:100%}.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar_x.mCS_x_hidden{margin-bottom:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal{width:auto;height:16px;top:auto;right:0;bottom:0;left:0}.mCustomScrollBox+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox+.mCSB_scrollTools.mCSB_scrollTools_horizontal{bottom:-26px}.mCSB_scrollTools.mCSB_scrollTools_horizontal a+.mCSB_draggerContainer{margin:0 20px}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:2px;margin:7px 0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger{width:30px;height:100%;left:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:4px;margin:6px auto}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{height:12px;margin:2px auto}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:8px;margin:4px 0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft,.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{display:block;position:absolute;width:20px;height:100%;overflow:hidden;margin:0 auto;cursor:pointer}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft{left:0}.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{right:0}.mCSB_container_wrapper{position:absolute;height:auto;width:auto;overflow:hidden;top:0;left:0;right:0;bottom:0;margin-right:30px;margin-bottom:30px}.mCSB_container_wrapper>.mCSB_container{padding-right:30px;padding-bottom:30px}.mCSB_vertical_horizontal>.mCSB_scrollTools.mCSB_scrollTools_vertical{bottom:20px}.mCSB_vertical_horizontal>.mCSB_scrollTools.mCSB_scrollTools_horizontal{right:20px}.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden+.mCSB_scrollTools.mCSB_scrollTools_vertical{bottom:0}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden+.mCSB_scrollTools~.mCSB_scrollTools.mCSB_scrollTools_horizontal{right:0}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_scrollTools.mCSB_scrollTools_horizontal{left:20px}.mCS-dir-rtl>.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden+.mCSB_scrollTools~.mCSB_scrollTools.mCSB_scrollTools_horizontal{left:0}.mCS-dir-rtl>.mCSB_inside>.mCSB_container_wrapper{margin-right:0;margin-left:30px}.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden>.mCSB_container{padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden>.mCSB_container{padding-bottom:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden{margin-right:0;margin-left:0}.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside>.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden{margin-bottom:0}.mCSB_scrollTools,.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonLeft,.mCSB_scrollTools .mCSB_buttonRight,.mCSB_scrollTools .mCSB_buttonUp,.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{-webkit-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;-moz-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;-o-transition:opacity .2s ease-in-out,background-color .2s ease-in-out;transition:opacity .2s ease-in-out,background-color .2s ease-in-out}.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail,.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail,.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar{-webkit-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;-moz-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;-o-transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out;transition:width .2s ease-out .2s,height .2s ease-out .2s,margin-left .2s ease-out .2s,margin-right .2s ease-out .2s,margin-top .2s ease-out .2s,margin-bottom .2s ease-out .2s,opacity .2s ease-in-out,background-color .2s ease-in-out}.mCSB_scrollTools{opacity:.75;filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCS-autoHide>.mCustomScrollBox>.mCSB_scrollTools,.mCS-autoHide>.mCustomScrollBox~.mCSB_scrollTools{opacity:0;filter:"alpha(opacity=0)";-ms-filter:"alpha(opacity=0)"}.mCS-autoHide:hover>.mCustomScrollBox>.mCSB_scrollTools,.mCS-autoHide:hover>.mCustomScrollBox~.mCSB_scrollTools,.mCustomScrollBox:hover>.mCSB_scrollTools,.mCustomScrollBox:hover~.mCSB_scrollTools,.mCustomScrollbar>.mCustomScrollBox>.mCSB_scrollTools.mCSB_scrollTools_onDrag,.mCustomScrollbar>.mCustomScrollBox~.mCSB_scrollTools.mCSB_scrollTools_onDrag{opacity:1;filter:"alpha(opacity=100)";-ms-filter:"alpha(opacity=100)"}.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.4);filter:"alpha(opacity=40)";-ms-filter:"alpha(opacity=40)"}.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.75);filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85);filter:"alpha(opacity=85)";-ms-filter:"alpha(opacity=85)"}.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9);filter:"alpha(opacity=90)";-ms-filter:"alpha(opacity=90)"}.mCSB_scrollTools .mCSB_buttonDown,.mCSB_scrollTools .mCSB_buttonLeft,.mCSB_scrollTools .mCSB_buttonRight,.mCSB_scrollTools .mCSB_buttonUp{background-image:url(mCSB_buttons.png);background-repeat:no-repeat;opacity:.4;filter:"alpha(opacity=40)";-ms-filter:"alpha(opacity=40)"}.mCSB_scrollTools .mCSB_buttonUp{background-position:0 0}.mCSB_scrollTools .mCSB_buttonDown{background-position:0 -20px}.mCSB_scrollTools .mCSB_buttonLeft{background-position:0 -40px}.mCSB_scrollTools .mCSB_buttonRight{background-position:0 -56px}.mCSB_scrollTools .mCSB_buttonDown:hover,.mCSB_scrollTools .mCSB_buttonLeft:hover,.mCSB_scrollTools .mCSB_buttonRight:hover,.mCSB_scrollTools .mCSB_buttonUp:hover{opacity:.75;filter:"alpha(opacity=75)";-ms-filter:"alpha(opacity=75)"}.mCSB_scrollTools .mCSB_buttonDown:active,.mCSB_scrollTools .mCSB_buttonLeft:active,.mCSB_scrollTools .mCSB_buttonRight:active,.mCSB_scrollTools .mCSB_buttonUp:active{opacity:.9;filter:"alpha(opacity=90)";-ms-filter:"alpha(opacity=90)"}.mCS-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:rgba(0,0,0,.85)}.mCS-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:rgba(0,0,0,.9)}.mCS-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px 0}.mCS-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -20px}.mCS-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -40px}.mCS-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -56px}.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-2.mCSB_scrollTools .mCSB_draggerRail{width:4px;background-color:#fff;background-color:rgba(255,255,255,.1);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:4px;background-color:#fff;background-color:rgba(255,255,255,.75);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:4px;margin:6px auto}.mCS-light-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-light-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-light-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)}.mCS-light-2.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px 0}.mCS-light-2.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -20px}.mCS-light-2.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -40px}.mCS-light-2.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -56px}.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px 0}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -20px}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -40px}.mCS-dark-2.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -56px}.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-thick.mCSB_scrollTools .mCSB_draggerRail{width:4px;background-color:#fff;background-color:rgba(255,255,255,.1);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px;background-color:#fff;background-color:rgba(255,255,255,.75);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:4px;margin:6px 0}.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:6px;margin:5px auto}.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-light-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-16px 0}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-16px -20px}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-20px -40px}.mCS-light-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-20px -56px}.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-96px 0}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-96px -20px}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-100px -40px}.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-100px -56px}.mCS-light-thin.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.1)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:2px}.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%}.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:2px;margin:7px auto}.mCS-dark-thin.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px 0}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -20px}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -40px}.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -56px}.mCS-rounded.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.15)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger,.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger,.mCS-rounded.mCSB_scrollTools .mCSB_dragger{height:14px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:14px;margin:0 1px}.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger{width:14px}.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{height:14px;margin:1px 0}.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{width:16px;height:16px;margin:-1px 0}.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:4px}.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{height:16px;width:16px;margin:0 -1px}.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:4px;margin:6px 0}.mCS-rounded.mCSB_scrollTools .mCSB_buttonUp{background-position:0 -72px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonDown{background-position:0 -92px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonLeft{background-position:0 -112px}.mCS-rounded.mCSB_scrollTools .mCSB_buttonRight{background-position:0 -128px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.15)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-80px -72px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-80px -92px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-80px -112px}.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-80px -128px}.mCS-rounded-dots-dark.mCSB_scrollTools_vertical .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_vertical .mCSB_draggerRail{width:4px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail{background-color:transparent;background-position:center}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAANElEQVQYV2NkIAAYiVbw//9/Y6DiM1ANJoyMjGdBbLgJQAX/kU0DKgDLkaQAvxW4HEvQFwCRcxIJK1XznAAAAABJRU5ErkJggg==);background-repeat:repeat-y;opacity:.3;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail{height:4px;margin:6px 0;background-repeat:repeat-x}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonUp{background-position:-16px -72px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonDown{background-position:-16px -92px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonLeft{background-position:-20px -112px}.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonRight{background-position:-20px -128px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAALElEQVQYV2NkIAAYSVFgDFR8BqrBBEifBbGRTfiPZhpYjiQFBK3A6l6CvgAAE9kGCd1mvgEAAAAASUVORK5CYII=)}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-96px -72px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-96px -92px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-100px -112px}.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-100px -128px}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-repeat:repeat-y;background-image:-moz-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,.5)),color-stop(100%,rgba(255,255,255,0)));background-image:-webkit-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-o-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-ms-linear-gradient(left,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:linear-gradient(to right,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{background-repeat:repeat-x;background-image:-moz-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,rgba(255,255,255,.5)),color-stop(100%,rgba(255,255,255,0)));background-image:-webkit-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-o-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:-ms-linear-gradient(top,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%);background-image:linear-gradient(to bottom,rgba(255,255,255,.5) 0,rgba(255,255,255,0) 100%)}.mCS-3d-dark.mCSB_scrollTools_vertical .mCSB_dragger,.mCS-3d.mCSB_scrollTools_vertical .mCSB_dragger{height:70px}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger{width:70px}.mCS-3d-dark.mCSB_scrollTools,.mCS-3d.mCSB_scrollTools{opacity:1;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_draggerRail{-webkit-border-radius:16px;-moz-border-radius:16px;border-radius:16px}.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools .mCSB_draggerRail{width:8px;background-color:#000;background-color:rgba(0,0,0,.2);box-shadow:inset 1px 0 1px rgba(0,0,0,.5),inset -1px 0 1px rgba(255,255,255,.2)}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#555}.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:8px}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:8px;margin:4px 0;box-shadow:inset 0 1px 1px rgba(0,0,0,.5),inset 0 -1px 1px rgba(255,255,255,.2)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{width:100%;height:8px;margin:4px auto}.mCS-3d.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-3d.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-3d.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-3d.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1);box-shadow:inset 1px 0 1px rgba(0,0,0,.1)}.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{box-shadow:inset 0 1px 1px rgba(0,0,0,.1)}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-3d-thick-dark.mCSB_scrollTools,.mCS-3d-thick.mCSB_scrollTools{opacity:1;filter:"alpha(opacity=30)";-ms-filter:"alpha(opacity=30)"}.mCS-3d-thick-dark.mCSB_scrollTools,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer,.mCS-3d-thick.mCSB_scrollTools,.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer{-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mCSB_inside+.mCS-3d-thick-dark.mCSB_scrollTools_vertical,.mCSB_inside+.mCS-3d-thick.mCSB_scrollTools_vertical{right:1px}.mCS-3d-thick-dark.mCSB_scrollTools_vertical,.mCS-3d-thick.mCSB_scrollTools_vertical{box-shadow:inset 1px 0 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.5)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal,.mCS-3d-thick.mCSB_scrollTools_horizontal{bottom:1px;box-shadow:inset 0 1px 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.5)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 1px 0 0 rgba(255,255,255,.4);width:12px;margin:2px;position:absolute;height:auto;top:0;bottom:0;left:0;right:0}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 0 1px 0 rgba(255,255,255,.4)}.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#555}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{height:12px;width:auto}.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer{background-color:#000;background-color:rgba(0,0,0,.05);box-shadow:inset 1px 1px 16px rgba(0,0,0,.1)}.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-3d-thick-dark.mCSB_scrollTools{box-shadow:inset 0 0 14px rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal{box-shadow:inset 0 1px 1px rgba(0,0,0,.1),inset 0 0 14px rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 1px 0 0 rgba(255,255,255,.4),inset -1px 0 0 rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{box-shadow:inset 0 1px 0 rgba(255,255,255,.4),inset 0 -1px 0 rgba(0,0,0,.2)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#777}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer{background-color:#fff;background-color:rgba(0,0,0,.05);box-shadow:inset 1px 1px 16px rgba(0,0,0,.1)}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCSB_outside+.mCS-minimal-dark.mCSB_scrollTools_vertical,.mCSB_outside+.mCS-minimal.mCSB_scrollTools_vertical{right:0;margin:12px 0}.mCustomScrollBox.mCS-minimal+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal-dark+.mCSB_scrollTools+.mCSB_scrollTools.mCSB_scrollTools_horizontal,.mCustomScrollBox.mCS-minimal-dark+.mCSB_scrollTools.mCSB_scrollTools_horizontal{bottom:0;margin:0 12px}.mCS-dir-rtl>.mCSB_outside+.mCS-minimal-dark.mCSB_scrollTools_vertical,.mCS-dir-rtl>.mCSB_outside+.mCS-minimal.mCSB_scrollTools_vertical{left:0;right:auto}.mCS-minimal-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-minimal.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent}.mCS-minimal-dark.mCSB_scrollTools_vertical .mCSB_dragger,.mCS-minimal.mCSB_scrollTools_vertical .mCSB_dragger{height:50px}.mCS-minimal-dark.mCSB_scrollTools_horizontal .mCSB_dragger,.mCS-minimal.mCSB_scrollTools_horizontal .mCSB_dragger{width:50px}.mCS-minimal.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.2);filter:"alpha(opacity=20)";-ms-filter:"alpha(opacity=20)"}.mCS-minimal.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-minimal.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.5);filter:"alpha(opacity=50)";-ms-filter:"alpha(opacity=50)"}.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.2);filter:"alpha(opacity=20)";-ms-filter:"alpha(opacity=20)"}.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.5);filter:"alpha(opacity=50)";-ms-filter:"alpha(opacity=50)"}.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools .mCSB_draggerRail{width:6px;background-color:#000;background-color:rgba(0,0,0,.2)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-light-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px}.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:6px;margin:5px 0}.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{width:12px}.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded+.mCSB_draggerRail,.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{height:12px;margin:2px 0}.mCS-light-3.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-light-3.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-dark-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1)}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-dark-3.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset.mCSB_scrollTools .mCSB_draggerRail{width:12px;background-color:#000;background-color:rgba(0,0,0,.2)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{width:6px;margin:3px 5px;position:absolute;height:auto;top:0;bottom:0;left:0;right:0}.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar,.mCS-inset.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{height:6px;margin:5px 3px;position:absolute;width:auto;top:0;bottom:0;left:0;right:0}.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail,.mCS-inset.mCSB_scrollTools_horizontal .mCSB_draggerRail{width:100%;height:12px;margin:2px 0}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset.mCSB_scrollTools .mCSB_buttonUp{background-position:-32px -72px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset.mCSB_scrollTools .mCSB_buttonDown{background-position:-32px -92px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset.mCSB_scrollTools .mCSB_buttonLeft{background-position:-40px -112px}.mCS-inset-2.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-3.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset.mCSB_scrollTools .mCSB_buttonRight{background-position:-40px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.1)}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonUp,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonUp{background-position:-112px -72px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonDown,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonDown{background-position:-112px -92px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonLeft,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonLeft{background-position:-120px -112px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonRight,.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonRight{background-position:-120px -128px}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail,.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail{background-color:transparent;border-width:1px;border-style:solid;border-color:#fff;border-color:rgba(255,255,255,.2);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail{border-color:#000;border-color:rgba(0,0,0,.2)}.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail{background-color:#fff;background-color:rgba(255,255,255,.6)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail{background-color:#000;background-color:rgba(0,0,0,.6)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.75)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.85)}.mCS-inset-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#000;background-color:rgba(0,0,0,.9)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.75)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.85)}.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar,.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar{background-color:#fff;background-color:rgba(255,255,255,.9)}.dropdown-menu{border:1px solid #ddd;background-color:#fff}.dropdown-menu li{border-top:1px solid #ddd;padding:2px 5px}.dropdown-menu li:first-child{border-top:none}.dropdown-menu .active,.dropdown-menu li:hover{background-color:#6eb7db}.textcomplete-wrapper{width:100%}.dropdown-menu{list-style:none;padding:0;margin:0}.dropdown-menu a:hover{cursor:pointer}.markItUp .markItUpButton1 a{background-image:url(../images/markitup/h1.png)}.markItUp .markItUpButton2 a{background-image:url(../images/markitup/h2.png)}.markItUp .markItUpButton3 a{background-image:url(../images/markitup/h3.png)}.markItUp .markItUpButton4 a{background-image:url(../images/markitup/bold.png)}.markItUp .markItUpButton5 a{background-image:url(../images/markitup/italic.png)}.markItUp .markItUpButton6 a{background-image:url(../images/markitup/stroke.png)}.markdown .markItUpButton7 a{background-image:url(../images/markitup/list-bullet.png)}.markdown .markItUpButton8 a{background-image:url(../images/markitup/list-numeric.png)}.markdown .markItUpButton9 a{background-image:url(../images/markitup/picture.png)}.markdown .markItUpButton10 a{background-image:url(../images/markitup/link.png)}.markdown .markItUpButton11 a{background-image:url(../images/markitup/quotes.png)}.markdown .markItUpButton12 a{background-image:url(../images/markitup/code.png)}.markdown .preview-icon a{background-image:url(../images/markitup/preview.png)}.markdown .help a{background-image:url(../images/markitup/help.png)}.markItUp *{margin:0;padding:0;outline:0}.markItUp a:link,.markItUp a:visited{color:#000;text-decoration:none}.markItUpContainer{font:11px Verdana,Arial,Helvetica,sans-serif}.markItUpEditor{font:12px 'Courier New',Courier,monospace;padding:5px;height:320px;clear:both;line-height:18px;overflow:auto}.markItUpPreviewFrame{overflow:auto;background-color:#FFF;width:99.9%;height:300px;margin:5px 0}.markItUpFooter{width:100%}.markItUpResizeHandle{overflow:hidden;width:22px;height:5px;margin-left:auto;margin-right:auto;background-image:url(../images/markitup/handle.png);cursor:n-resize}.markItUp .markItUpHeader ul{margin:0}.markItUpHeader ul li{list-style:none;position:relative;margin:3px}.markItUpHeader ul li:hover>ul{display:block}.markItUpHeader ul .markItUpDropMenu{background:url(../images/markitup/menu.png) 115% 50% no-repeat;margin-right:5px}.markItUpHeader ul .markItUpDropMenu li{margin-right:0}.markItUpHeader ul ul{display:none;position:absolute;top:18px;left:0;background:#FFF;border:1px solid #000}.markItUpHeader ul ul li{float:none;border-bottom:1px solid #000}.markItUpHeader ul ul .markItUpDropMenu{background:url(../images/markitup/submenu.png) 100% 50% no-repeat #FFF}.markItUpHeader ul .markItUpSeparator{margin:2px 10px 0;width:1px;height:16px;overflow:hidden;background-color:#CCC}.markItUpHeader ul ul .markItUpSeparator{width:auto;height:1px;margin:0}.markItUpHeader ul ul ul{position:absolute;top:-1px;left:150px}.markItUpHeader ul ul ul li{float:none}.markItUpHeader ul a{display:block;width:16px;height:16px;text-indent:-10000px;background-repeat:no-repeat;padding:3px;margin:0}.markItUpHeader ul ul a{display:block;text-indent:0;width:120px;padding:5px 5px 5px 25px;background-position:2px 50%}.markItUpHeader ul ul a:hover{color:#FFF;background-color:#000}/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}mark{background:#ff0;color:#000}sub,sup{line-height:0;position:relative}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}hr{-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{overflow:auto}optgroup{font-weight:700}/*! * Pikaday * Copyright © 2014 David Bushell | BSD & MIT license | http://dbushell.com/ - */.pika-single{display:block;position:relative;width:240px;padding:8px;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-disabled .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff!important;background:#ff8000!important;box-shadow:none!important;border-radius:3px!important}.hll{background-color:#ffc}.c{color:#998;font-style:italic}.err{background-color:#e3d2d2;color:#a61717}.k,.o{color:#000;font-weight:700}.cm{color:#998;font-style:italic}.cp{color:#999;font-style:italic;font-weight:700}.c1{color:#998;font-style:italic}.cs{color:#999;font-style:italic;font-weight:700}.gd{background-color:#fdd;color:#000}.ge{color:#000;font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{background-color:#dfd;color:#000}.go{color:#888}.gp{color:#555}.gs{font-weight:700}.gu{color:#aaa}.gt{color:#a00}.kc,.kd,.kn,.kp,.kr{color:#000;font-weight:700}.kt{color:#458;font-weight:700}.m{color:#099}.s{color:#d01040}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:700}.no{color:teal}.nd{color:#3c5d5d;font-weight:700}.ni{color:purple}.ne,.nf,.nl{color:#900;font-weight:700}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{color:#000;font-weight:700}.w{color:#bbb}.mf,.mh,.mi,.mo{color:#099}.s2,.sb,.sc,.sd,.se,.sh,.si,.sx{color:#d01040}.sr{color:#009926}.s1{color:#d01040}.ss{color:#990073}.bp{color:#999}.vc,.vg,.vi{color:teal}.il{color:#099}*{box-sizing:border-box}a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{border:0;font:inherit;font-size:100%;margin:0;padding:0;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:''}table{border-collapse:collapse;border-spacing:0}body{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.icon{font-family:taiga}html{min-height:100%;width:100%}body{background:#fff;color:#444;min-height:100%;width:100%}body .master.ng-animate{-webkit-transition:0;transition:0}body .menu,body.open-projects-nav .projects-nav{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .master{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .master.ng-animate{-webkit-transition:0;transition:0}body.open-projects-nav .menu{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .projects-nav-overlay{opacity:.9;-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:all 1s ease;transition:all 1s ease}body.open-projects-nav.closed-projects-nav .projects-nav{-webkit-transform:translate3d(-300px,0,0);transform:translate3d(-300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav.closed-projects-nav .projects-nav-overlay{opacity:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:all 1s ease;transition:all 1s ease}body.open-projects-nav.closed-projects-nav .master,body.open-projects-nav.closed-projects-nav .menu{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}body.loading-project{overflow:hidden}body.loading-project .projects-nav-overlay{opacity:1;overflow:hidden;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}body.loading-project .projects-nav-overlay div{opacity:1;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}.loader-active{overflow:hidden}.master{background:#fff;height:100%;min-height:100%;position:relative}.wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-height:100vh;padding-left:90px}.menu-secondary{background:#f5f5f5;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;min-height:100vh;min-width:0;padding:2rem 1rem;width:320px}.menu-secondary.filters-bar{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;padding:0;-webkit-transition:all .2s linear;transition:all .2s linear;width:0}.menu-secondary.filters-bar.active{padding:2em 1em;-webkit-transition:all .2s linear;transition:all .2s linear;width:260px}.menu-secondary.filters-bar.active .filters-inner{opacity:1;-webkit-transition:all .4s ease-in;transition:all .4s ease-in}.menu-tertiary{background-color:#8b9e8d;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;min-height:100vh;padding:2em 1em;width:255px}.extrabar{background:#f5f5f5}.main{-webkit-box-flex:4;-webkit-flex:4;-ms-flex:4;flex:4;min-width:600px;padding:2rem 2rem 1rem}.hidden{display:none!important}.header-with-actions{-webkit-align-content:stretch;-ms-flex-line-pack:stretch;align-content:stretch;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:1rem}.header-with-actions .action-buttons{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.header-with-actions .button{color:#fff;float:right;margin-left:10px}.header-with-actions .button:hover{color:#fff}.header-with-actions h1{margin-bottom:0}@-webkit-keyframes loading{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0}100%{-webkit-filter:blur(0);filter:blur(0);opacity:1}}@keyframes loading{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0}100%{-webkit-filter:blur(0);filter:blur(0);opacity:1}}@-webkit-keyframes formSlide{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0;-webkit-transform:translateY(10rem);transform:translateY(10rem)}50%{-webkit-filter:blur(0);filter:blur(0)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes formSlide{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0;-webkit-transform:translateY(10rem);transform:translateY(10rem)}50%{-webkit-filter:blur(0);filter:blur(0)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes loadBar{0%{-webkit-box-flex:1;-webkit-flex:1;flex:1}10%{-webkit-box-flex:10;-webkit-flex:10;flex:10}20%{-webkit-box-flex:1;-webkit-flex:1;flex:1}}@keyframes loadBar{0%{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}10%{-webkit-box-flex:10;-webkit-flex:10;-ms-flex:10;flex:10}20%{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}}h2{font-size:2rem}h1,h1 span{font-size:3rem}h1,h2{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}@font-face{font-family:OpenSans-CondLight;src:url(../fonts/OpenSans-CondLight.eot?#iefix) format("embedded-opentype"),url(../fonts/OpenSans-CondLight.woff) format("woff"),url(../fonts/OpenSans-CondLight.ttf) format("truetype"),url(../fonts/OpenSans-CondLight.svgOpenSans-CondLight) format("svg")}@font-face{font-family:opensans-regular;src:url(../fonts/opensans-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/opensans-regular.woff) format("woff"),url(../fonts/opensans-regular.ttf) format("truetype"),url(../fonts/opensans-regular.svgopensans-regular) format("svg")}@font-face{font-family:opensans-semibold;src:url(../fonts/opensans-semibold.eot?#iefix) format("embedded-opentype"),url(../fonts/opensans-semibold.woff) format("woff"),url(../fonts/opensans-semibold.ttf) format("truetype"),url(../fonts/opensans-semibold.svgopensans-semibold) format("svg")}@font-face{font-family:taiga;src:url(../fonts/taiga.eot?#iefix) format("embedded-opentype"),url(../fonts/taiga.woff) format("woff"),url(../fonts/taiga.ttf) format("truetype"),url(../fonts/taiga.svgtaiga) format("svg")}h1,h2,h3,h4,h5,h6{color:#050505;font-weight:400}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}h1{line-height:3.4rem;margin-bottom:1rem;text-transform:uppercase}h1 span{line-height:3.4rem;margin-right:.5rem;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap}h1 span.green,h1 span:last-child{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}h1 .project-name{display:inline-block;max-width:60%}h1 .project-name-short{display:inline-block;max-width:40%}h1 .green{color:#72a114}h1 .date{max-width:500px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#b8b8b8}h2{margin-bottom:1rem}p{margin:0 0 20px}p img{margin:0}em{font-style:italic}strong{font-weight:700}hr{border:solid #ddd;border-width:1px 0 0;clear:both;height:0;margin:10px 0 30px}a,a:visited{color:#444;text-decoration:none}a:hover,a:visited:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}[data-icon]:before{content:attr(data-icon);font-family:taiga!important;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal!important;font-variant:normal!important;font-weight:400!important;line-height:1;speak:none;text-transform:none!important}[class*=' icon-']:before,[class^=icon-]:before{font-family:taiga!important;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal!important;font-variant:normal!important;font-weight:400!important;line-height:1;speak:none;text-transform:none!important}.icon-bug:before{content:'a'}.icon-copy:before{content:'b'}.icon-minimize:before{content:'c'}.icon-maximize:before{content:'d'}.icon-comment:before{content:'e'}.icon-plus:before{content:'f'}.icon-attachments:before{content:'g'}.icon-edit:before{content:'h'}.icon-documents:before{content:'i'}.icon-delete:before{content:'j'}.icon-arrow-bottom:before{content:'k'}.icon-arrow-left:before{content:'l'}.icon-arrow-right:before{content:'m'}.icon-arrow-up:before{content:'n'}.icon-briefcase:before{content:'o'}.icon-caret-down:before{content:'p'}.icon-caret-up:before{content:'q'}.icon-check-square:before{content:'r'}.icon-notification-error:before{content:'s'}.icon-settings:before{content:'t'}.icon-document:before{content:'u'}.icon-warning:before{content:'v'}.icon-move:before{content:'w'}.icon-drag-h:before{content:'x'}.icon-drag-v:before{content:'y'}.icon-filter:before{content:'z'}.icon-github:before{content:'A'}.icon-help:before{content:'B'}.icon-reload:before{content:'C'}.icon-writer:before{content:'D'}.icon-stats:before{content:'E'}.icon-floppy:before{content:'F'}.icon-idea:before{content:'G'}.icon-warning-alt:before{content:'H'}.icon-video:before{content:'I'}.icon-bulk:before{content:'K'}.icon-vunfold:before{content:'M'}.icon-tasks:before{content:'O'}.icon-kanban:before{content:'P'}.icon-search:before{content:'Q'}.icon-wiki:before{content:'L'}.icon-team:before{content:'T'}.icon-spinner:before{content:'J'}.icon-vfold:before{content:'N'}.icon-issues:before{content:'U'}.icon-backlog:before{content:'R'}.icon-iocaine:before{content:'S'}.icon-closed-eye:before{content:'V'}.icon-open-eye:before{content:'W'}.icon-archive:before{content:'X'}.icon-capslock:before{content:'Y'}.icon-upload:before{content:'Z'}.login-main .tagline{font-size:2rem}.login-main .logo{font-size:3rem}.login-main .logo,.login-main .tagline{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.login-main{background:url(/images/bg.png) center center no-repeat;background-size:cover;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.login-main fieldset{margin-bottom:.5rem}.login-main .login-container{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px}.login-main .logo-svg{padding:0 33%;text-align:center;width:100%}.login-main .logo{color:#fff;margin-bottom:1rem;text-align:center}.login-main .tagline{color:#fff;line-height:2rem;margin-bottom:1rem;text-align:center;text-transform:uppercase}.login-main form{margin-bottom:1rem}.login-main input{background:#fff}.login-main input::-webkit-input-placeholder{color:#b8b8b8}.login-main input::-moz-placeholder{color:#b8b8b8}.login-main input:-moz-placeholder{color:#b8b8b8}.login-main input:-ms-input-placeholder{color:#b8b8b8}.login-main .login-text,.login-main .register-text{text-align:center}.login-main .login-text a:hover,.login-main .register-text a:hover{color:#9dce0a}.login-main .button{color:#fff;display:block;text-align:center}.login-main a:hover{color:#fff}.login-main .checksley-error-list{right:1rem}.login-main .checksley-error-list+.forgot-pass{display:none}.invitation-main .invitation-form .forgot-pass,.invitation-main .register-text{font-size:.8rem}.invitation-main .avatar .person-name,.invitation-main .invitation-text{font-size:2rem}.invitation-main .invitation-text .project-name{font-size:3rem}.invitation-main .avatar .person-name,.invitation-main .invitation-text{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.invitation-main{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.invitation-main .invitation-container{-webkit-flex-basis:650px;-ms-flex-preferred-size:650px;flex-basis:650px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:650px}.invitation-main .logo{margin:1rem auto;width:150px}.invitation-main .avatar{margin:0 auto 1rem;text-align:center;width:250px}.invitation-main .avatar .person-name{color:#fff;text-transform:uppercase}.invitation-main .avatar img{display:block;text-align:center;width:50px}.invitation-main .invitation-text{color:#fff;line-height:2rem;text-align:center;text-transform:uppercase}.invitation-main .invitation-text .project-name{display:block}.invitation-main .invitation-form{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.invitation-main .invitation-form fieldset{margin-bottom:.5rem}.invitation-main .invitation-form input{background:#fff;color:#555;position:relative}.invitation-main .invitation-form input::-webkit-input-placeholder{color:#b8b8b8}.invitation-main .invitation-form input::-moz-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:-moz-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:-ms-input-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:focus+.forgot-pass{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.invitation-main .invitation-form .forgot-pass{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.invitation-main .invitation-form .forgot-pass:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.invitation-main .invitation-form .button{color:#fff;display:block;text-align:center}.invitation-main .invitation-form .button:hover{background:#9dce0a}.invitation-main .invitation-form .button-github:hover{background:#000}.invitation-main .login-form,.invitation-main .register-form{-webkit-flex-basis:200px;-ms-flex-preferred-size:200px;flex-basis:200px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:1rem;text-align:center;width:200px}.invitation-main .login-form .form-header,.invitation-main .register-form .form-header{color:#999}.invitation-main .register-form fieldset:last-child{margin-bottom:1rem}.invitation-main .register-text{color:#fff}.invitation-main .register-text a{color:#72a114}.invitation-main .register-text a:hover{color:#9dce0a}.invitation-main .login-form{border-right:1px solid #fff}blockquote cite,sup{font-size:.8rem}.empty span.title{font-size:2rem}.empty .icon{font-size:3rem}.empty span.title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}blockquote,blockquote p{color:#777;font-style:italic;line-height:24px}blockquote{border-left:1px solid #ddd;margin:0 0 20px;padding:9px 20px 0 19px}blockquote cite{color:#555;display:block}blockquote cite:before{content:'\2014 \0020'}ol,ul{margin-bottom:20px}ul{list-style:none}ol{list-style:decimal}sup{vertical-align:super}.icon{vertical-align:middle}.icon-spinner{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.clickable{cursor:pointer}.not-clickable{cursor:default}.draggable{cursor:move}.pika-single{z-index:999999}.pika-single .pika-title{color:#444}.pika-single .is-selected .pika-button{background:#72a114;border-radius:0!important;box-shadow:inset 0 1px 3px #72a114}.pika-single .is-today .pika-button{color:#72a114}.pika-single .is-today.is-selected button{color:#fff}.pika-single .pika-button:hover{background:#9dce0a!important;border-radius:0!important;box-shadow:inset 0 1px 3px #9dce0a!important}.empty{border:1px dashed #b8b8b8;color:#b8b8b8;min-height:10rem;padding:5% 0;text-align:center}.empty .icon{margin-bottom:2rem}.empty span{display:block}.empty span.title{margin-bottom:1rem;text-transform:uppercase}.checksley-error-list{font-size:.8rem}input[type=number],input[type=text],input[type=password],input[type=email],input[type=date],select,textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}fieldset{border:0;margin:0;padding:0;position:relative;width:100%}fieldset label~.checksley-error-list{top:31px}input[type=number],input[type=text],input[type=password],input[type=email],input[type=date],select,textarea{background:#f5f5f5;border:1px solid #b8b8b8;color:#444;margin:0;padding:8px;width:100%}input[type=number]::-webkit-input-placeholder,input[type=text]::-webkit-input-placeholder,input[type=password]::-webkit-input-placeholder,input[type=email]::-webkit-input-placeholder,input[type=date]::-webkit-input-placeholder,select::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#b8b8b8}input[type=number]::-moz-placeholder,input[type=text]::-moz-placeholder,input[type=password]::-moz-placeholder,input[type=email]::-moz-placeholder,input[type=date]::-moz-placeholder,select::-moz-placeholder,textarea::-moz-placeholder{color:#b8b8b8}input[type=number]:-moz-placeholder,input[type=text]:-moz-placeholder,input[type=password]:-moz-placeholder,input[type=email]:-moz-placeholder,input[type=date]:-moz-placeholder,select:-moz-placeholder,textarea:-moz-placeholder{color:#b8b8b8}input[type=number]:-ms-input-placeholder,input[type=text]:-ms-input-placeholder,input[type=password]:-ms-input-placeholder,input[type=email]:-ms-input-placeholder,input[type=date]:-ms-input-placeholder,select:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#b8b8b8}textarea{min-height:10rem;resize:vertical}.checksley-error-list{margin-bottom:0;position:absolute;right:2rem;top:10px}.checksley-error-list li{color:red;padding:.2rem}.error-main{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.error-main .error-container{color:#fff;-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;text-align:center}.error-main .logo-svg{padding:0 32%;text-align:center;width:100%}.error-main h1{color:#fff;margin-bottom:3rem}.error-main a{color:#72a114}.error-main a:hover{color:#9dce0a}.backlog .new-us{float:right}.backlog-menu{background:#f5f5f5;color:#050505;margin-bottom:1rem;padding:.5rem}.backlog-menu:after{clear:both;content:'';display:table}.backlog-menu .trans-button{display:inline-block;margin-right:1rem;padding:.3rem 0}.backlog-menu .trans-button.move-to-current-sprint{display:none}.backlog-menu .trans-button span{vertical-align:middle}.taskboard .graphics-container{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow-y:hidden}.taskboard .graphics-container.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:300px}.duty-data-container,.points-per-role .popover a,.points-per-role .popover.fix a,.us-detail-progress-bar .tasks-completed,.us-status .priority-data .pop-priority a,.us-status .severity-data .pop-severity a,.us-status .status-data .pop-status a,.us-status .type-data .pop-type a,.us-story-main-data .us-title .block-desc-container,.us-story-main-data .us-title .us-related-task{font-size:.8rem}.us-detail-status,.us-story-main-data .us-title,.us-story-main-data .us-title .icon-edit,.us-story-main-data .us-title .icon-floppy,.us-story-main-data .us-title .icon-spinner{font-size:1.2rem}.blocked-warning .blocked,.blocked-warning .icon,.issue-nav a,.points-per-role .points,.us-story-main-data .us-title .us-name,.us-story-main-data .us-title .us-number{font-size:2rem}.blocked-warning .blocked,.points-per-role .points,.us-story-main-data .us-title .us-number{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.points-per-role .popover,.points-per-role .popover.fix,.us-status .priority-data .pop-priority,.us-status .severity-data .pop-severity,.us-status .status-data .pop-status,.us-status .type-data .pop-type,.us-story-main-data .us-title{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.us-story-main-data .us-title .block-description-title,.us-story-main-data .us-title.blocked .unblock{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.us-story-main-data{margin-bottom:2rem}.us-story-main-data .us-title{background:#f5f5f5;margin-bottom:.5rem;padding:1rem;position:relative;-webkit-transition:all .2s linear;transition:all .2s linear}.us-story-main-data .us-title.blocked{background:red;-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:middle}.us-story-main-data .us-title.blocked .us-title-text,.us-story-main-data .us-title.blocked input{margin-bottom:.5rem}.us-story-main-data .us-title.blocked .us-name,.us-story-main-data .us-title.blocked .us-number,.us-story-main-data .us-title.blocked .us-related-task{color:#fff}.us-story-main-data .us-title.blocked a{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title.blocked a:hover{color:#ff8282}.us-story-main-data .us-title.blocked .unblock{color:#fff;float:right}.us-story-main-data .us-title.blocked .unblock:hover{color:#ff8282;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title p{margin-bottom:0}.us-story-main-data .us-title .us-edit-name-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.us-story-main-data .us-title .edit-subject{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.us-story-main-data .us-title input{background:#fff;-webkit-box-flex:9;-webkit-flex-grow:9;-ms-flex-positive:9;flex-grow:9}.us-story-main-data .us-title .save-container{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.us-story-main-data .us-title .us-title-text{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:0;max-width:94%}.us-story-main-data .us-title .us-title-text:hover .icon-edit{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.us-story-main-data .us-title .us-number{color:#b8b8b8;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;line-height:2.2rem;margin-right:.5rem}.us-story-main-data .us-title .us-name{color:#444;display:inline-block;line-height:2.2rem;padding-right:1rem;width:100%}.us-story-main-data .us-title .icon-edit,.us-story-main-data .us-title .icon-floppy,.us-story-main-data .us-title .icon-spinner{color:#b8b8b8;margin-left:.5rem}.us-story-main-data .us-title .icon-edit{opacity:0}.us-story-main-data .us-title .us-related-task{color:#b8b8b8;margin-top:.5rem}.us-story-main-data .us-title .us-related-task a{border-left:1px solid #b8b8b8;padding:0 .2rem;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title .us-related-task a:hover{color:#72a114}.us-story-main-data .us-title .us-related-task a:first-child{border:0}.us-story-main-data .us-title .block-description-title{color:#fff;margin-right:.5rem}.us-story-main-data .us-title .block-description{color:#fff;display:inline-block;margin-right:5rem}.blocked-warning{margin-bottom:1rem}.blocked-warning .blocked{color:red;line-height:2.5rem;margin-bottom:.5rem}.blocked-warning .icon{vertical-align:middle}.blocked-warning .block-description{color:#444;margin:0}.issue-nav{position:absolute;right:1rem;top:1rem}.duty-content{position:relative}.duty-content:hover .view-description .edit{opacity:1;top:-1.5rem;-webkit-transition:all .2s linear;transition:all .2s linear}.duty-content:hover .view-description .editable{background:#f5f5f5;cursor:pointer}.duty-content:hover .view-description .no-description{color:#444}.duty-content.wysiwyg{overflow:visible}.duty-content .no-description{color:#b8b8b8}.duty-content textarea{background:#fff;height:10rem}.duty-content .save-container{position:absolute;right:1rem;top:.2rem}.duty-content .save-container .save{color:#050505;opacity:.6;top:0}.duty-content .save-container:hover{opacity:.3;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.duty-content .edit{color:#444}.duty-content .view-description .edit{background:#f5f5f5;left:0;opacity:0;padding:.2rem .5rem;position:absolute;top:0;-webkit-transition:all .2s linear;transition:all .2s linear}.duty-content .edit-description .save{top:.4rem}.duty-content .edit-description .edit{position:absolute;right:2.5rem;top:.4rem;-webkit-transition:all .2s linear;transition:all .2s linear}.comment-list{padding:1rem}.us-detail-status{color:#72a114;vertical-align:middle}.us-detail-progress-bar{background:#444;height:26px;margin-bottom:1rem;position:relative}.us-detail-progress-bar .current-progress{background:#9dce0a;height:26px;left:0;position:absolute;top:0;width:60%}.us-detail-progress-bar .tasks-completed{color:#fff;left:10px;position:absolute;top:2px}.points-per-role{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative}.points-per-role>li{border-right:1px solid rgba(68,68,68,.3);color:rgba(68,68,68,.3);display:inline-block;-webkit-flex-basis:18%;-ms-flex-preferred-size:18%;flex-basis:18%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin:.5rem .1rem;position:relative;text-align:center;-webkit-transition:color .3s linear;transition:color .3s linear;width:18%}.points-per-role>li.active{color:#72a114}.points-per-role>li:first-child{opacity:1}.points-per-role>li:last-child{border:0}.points-per-role .points{display:block;text-align:center}.points-per-role .role{display:inline-block;max-width:90%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}.points-per-role .popover{background:#050505;color:#fff;display:none;left:35%;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.points-per-role .popover a{border-bottom:1px solid #444;color:#fff;padding:10px 2px}.points-per-role .popover a:last-child{border:0}.points-per-role .popover a:hover{-webkit-transition:color .3s linear;transition:color .3s linear}.points-per-role .popover:after{background:#050505;content:'';height:15px;left:10px;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.points-per-role .popover li{display:inline-block;width:23%}.points-per-role .popover a{display:block;text-align:center}.points-per-role .popover a.active,.points-per-role .popover a:hover{background:#9dce0a;color:#fff}.points-per-role .popover.fix{background:#050505;color:#fff;display:none;left:-160px;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.points-per-role .popover.fix a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.points-per-role .popover.fix a:last-child{border:0}.points-per-role .popover.fix a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.points-per-role .popover.fix:after{background:#050505;content:'';height:15px;left:90%;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.duty-data-container{margin-bottom:1rem}.duty-data-container .duty-data{margin-bottom:.5rem}.duty-data-container .duty-data:last-child{margin:0}.duty-data-container .duty-data div{background:#e8e8e8;padding:.5rem 1rem .5rem .5rem;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.duty-data-container .duty-data .clickable:hover{background:#dcdcdc;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.duty-data-container .level{display:inline-block;margin-right:.5rem;vertical-align:top}.duty-data-container .level-name{color:#c2c2c2;float:right}.duty-data-container .level-name.loading span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.us-detail-settings{margin-top:2rem}.us-detail-settings .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center;width:100%}.us-detail-settings .button-gray,.us-detail-settings .button-gray:hover{background:#b8b8b8}.us-detail-settings .button-gray.editable:hover{background:#444;cursor:pointer}.us-detail-settings .button-gray.active{background:#72a114}.us-detail-settings .item-block.editable:hover{background:red;cursor:pointer}.us-detail-settings .button-red.active,.us-detail-settings .button-red:hover{background:red}.us-detail-settings label.editable{cursor:pointer}.us-detail-settings label+input{display:none}.us-detail-settings span.button-gray,.us-detail-settings span.button-gray:hover{background:#b8b8b8}.us-detail-settings span.button-gray.active,.us-detail-settings span.button-gray:hover.active{background:#555}.us-detail-settings span.button-red,.us-detail-settings span.button-red:hover{background:#ff8282}.us-detail-settings span.button-red.active,.us-detail-settings span.button-red:hover.active{background:red}.us-status .type-data{position:relative}.us-status .type-data .pop-type{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .type-data .pop-type a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .type-data .pop-type a:last-child{border:0}.us-status .type-data .pop-type a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .type-data .pop-type:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .severity-data{position:relative}.us-status .severity-data .pop-severity{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .severity-data .pop-severity a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .severity-data .pop-severity a:last-child{border:0}.us-status .severity-data .pop-severity a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .severity-data .pop-severity:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .priority-data{position:relative}.us-status .priority-data .pop-priority{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .priority-data .pop-priority a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .priority-data .pop-priority a:last-child{border:0}.us-status .priority-data .pop-priority a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .priority-data .pop-priority:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .status-data{position:relative}.us-status .status-data .pop-status{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .status-data .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .status-data .pop-status a:last-child{border:0}.us-status .status-data .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .status-data .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.admin-membership header:after{clear:both;content:'';display:table}.admin-membership header a{float:right}.admin-roles p{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-roles header{position:relative}.admin-roles h1{margin-bottom:0}.admin-roles p{color:#b8b8b8}.project-values-options{margin-bottom:1rem;text-align:right}.project-colors .new-color{float:right}.project-colors .colors-table{margin-top:1rem}.project-colors .project-colors-options:after{clear:both;content:'';display:table}.kanban .kanban-settings{float:right}.kanban .burndown-container{display:none}.kanban .list-filters{margin-bottom:1rem}.issues .filters-bar{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:260px}.issues .filters-inner{opacity:1;padding:2em 1em}.wiki .remove{font-size:.8rem;color:#b8b8b8}.wiki .remove:hover span{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}.wiki .remove:hover .icon{color:red;-webkit-transition:color .2s linear;transition:color .2s linear}.wiki .remove .icon{color:#b8b8b8;margin-right:.2rem}.wiki-content{margin-bottom:2rem;position:relative}.wiki-content .view-wiki-content:hover .wysiwyg{background:#f5f5f5;cursor:pointer}.wiki-content .view-wiki-content:hover .edit{opacity:1;top:-1.5rem;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .view-wiki-content .edit{background:#f5f5f5;left:0;opacity:0;padding:.2rem .5rem;position:absolute;top:0;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .edit-wiki-content .icon:hover{color:#444;opacity:.3;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .edit-wiki-content .preview-icon{position:absolute;right:3.5rem}.wiki-content .edit-wiki-content .action-container{position:absolute;right:1rem;top:.3rem}.wiki-content .edit-wiki-content .edit{position:absolute;right:3.5rem;top:.4rem}.wysiwyg{margin-bottom:2rem}.wysiwyg textarea{background:#fff;max-height:none}.save-wiki{float:right}.team h2{margin:1rem 0}.team h2 span:last-child{color:#72a114}.button,.button-github,a.button-bulk,a.button-bulk .icon{font-size:1rem}.button-github .icon,.trans-button{font-size:1.2rem}.button,.button-github,.trans-button,a.button-bulk{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.button,.button-github,a.button-bulk{display:inline-block;padding:7px 40px 6px;-webkit-transition:background .3s linear;transition:background .3s linear;text-transform:uppercase}.button-github:hover,.button:hover,a.button-bulk:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.loading.button span,.loading.button-github span,a.loading.button-bulk span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.button .icon,.button-github .icon,a.button-bulk .icon{margin-right:.3rem}.trans-button{text-transform:uppercase}.trans-button.active,.trans-button:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.trans-button .icon{margin-right:.3rem}a.button-green{background:#72a114;color:#fff;vertical-align:middle}a.button-green.active,a.button-green:hover{background:#9dce0a}a.button-green span{color:#fff}.button-gray,a.button-gray{background:#585858}.button-gray:hover,a.button-gray:hover{background:#9dce0a;color:#fff}.button-gray span,a.button-gray span{color:#fff}a.button-blackish{background:#050505;color:#f5f5f5}a.button-blackish:hover{background:#879b89;color:#fff}a.button-blackish span{color:#fff}a.button-red{background:#ff8282}a.button-red:hover{background:red;color:#fff}a.button-red span{color:#fff}a.button-orange{background:#d98a0b}a.button-orange:hover{background:#f4a423;color:#fff}a.button-orange span{color:#fff}a.button-block{background:#fff;color:red}a.button-block:hover{background:#ff8282;color:#fff}a.button-bulk{background:#72a114;font-size:22px;margin-left:2px;padding:.3rem .5rem;vertical-align:middle}a.button-bulk .icon{color:#fff;margin-right:0}a.button-bulk:hover{background:#9dce0a;-webkit-transition:background .3s linear;transition:background .3s linear}.button-github{background:#444;vertical-align:middle}.button-github .icon{color:#fff;margin-right:.5rem;vertical-align:text-bottom}.button-github:hover{background:#000;-webkit-transition:background .3s linear;transition:background .3s linear}.avatar img{border:2px solid #fff;border-radius:8%;width:100%}.summary .description{font-size:.8rem}.summary .icon{font-size:1.2rem}.large-summary .icon,.summary .number{font-size:2rem}.summary .description{font-family:opensans-regular,Arial,Helvetica,sans-serif}.summary .number{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.summary{background:#444;color:#fff;margin-bottom:2rem;padding:1em}.summary:after{clear:both;content:'';display:table}.summary ul{display:inline-block;margin:0;padding:0}.summary li{display:inline-block;margin-right:1rem}.summary .data{float:left;margin-right:1em;margin-top:4px}.summary .data .number{color:#9dce0a;top:0}.summary .icon{float:left}.summary .number{float:left;margin-right:.3rem;position:relative;top:5px}.summary .description{float:left;line-height:.9rem}.summary-progress-bar{background:#f5f5f5;float:left;height:30px;margin-bottom:0;margin-right:10px;padding:3px;position:relative;width:15%}.summary-progress-bar .current-progress{background:#9dce0a;height:24px}.summary-progress-bar .defined-points{background:#ff8282;height:24px;position:absolute;width:calc(100% - 6px)}.summary-progress-bar .project-points-progress{background:#fff;height:24px;position:absolute}.summary-progress-bar .closed-points-progress{background:#9dce0a;height:24px;position:absolute}.large-summary ul{border-right:1px solid #f5f5f5;margin-right:1rem;vertical-align:top}.large-summary ul:last-of-type{border:0;margin:0}.large-summary .icon{margin-right:.4rem}.large-summary .icon.icon-stats{color:#555;float:right;-webkit-transition:color .3s linear;transition:color .3s linear}.large-summary .icon.icon-stats:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.large-summary .icon.icon-stats.active{color:#9dce0a}.large-summary .icon.icon-stats.active:hover{color:#555;-webkit-transition:color .3s linear;transition:color .3s linear}.tags-block .add-tag-text,.tags-block .tag{font-size:.8rem}.tags-block .icon-plus{font-size:1.2rem}.tag{background:#f5f5f5;color:#444;display:inline-block;margin-right:.5rem;padding:.2rem .5rem;text-align:center}.tag .icon-delete{color:#b8b8b8;margin-left:1rem}.tag .icon-delete:hover{color:red}.ui-autocomplete{background:#fff;border:1px solid #b8b8b8;z-index:99910}.ui-autocomplete .ui-state-focus{background:#9dce0a}.ui-helper-hidden-accessible{display:none}.tags-block .tags-container{display:inline-block}.tags-block input{padding:.4rem;width:14rem}.tags-block .tag{margin:0 .5rem .5rem 0;padding:.5rem}.tags-block .add-tag{color:#b8b8b8}.tags-block .add-tag:hover{color:#9dce0a}.single-filter{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;cursor:pointer;display:block;height:32px;margin-bottom:1rem;opacity:.5;position:relative}.single-filter:after{clear:both;content:'';display:table}.single-filter.active,.single-filter.selected,.single-filter:hover{color:#444;opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.single-filter .name,.single-filter .number{padding:8px 10px}.single-filter .name{background:#dcdcdc;display:block;width:100%}.single-filter .number{background:#c2c2c2;position:absolute;right:0;top:0}.single-filter .icon-delete{color:#444;position:absolute;right:.5rem;top:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.single-filter .icon-delete:hover{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-task .task-assigned,.taskboard-task .taskboard-text,.taskboard-task .taskboard-user-avatar a{font-size:.8rem}.taskboard-task .icon-drag-h,.taskboard-task .icon-edit,.taskboard-task .icon-iocaine{font-size:1.2rem}.taskboard-task .icon-drag-h{font-size:2rem}.taskboard-task .task-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.taskboard-task{background:#fff8e4;border:1px solid #f1e8cd;box-shadow:none;cursor:move;margin:.2rem;min-height:7rem;position:relative}.taskboard-task:hover .icon-drag-h,.taskboard-task:hover .icon-edit{color:#e4d6ad;display:block;opacity:1;-webkit-transition:color .3s linear,opacity .3s linear;transition:color .3s linear,opacity .3s linear}.taskboard-task.ui-sortable-helper{box-shadow:1px 1px 15px rgba(0,0,0,.4);-webkit-transition:box-shadow .3s linear;transition:box-shadow .3s linear}.taskboard-task.ui-sortable-placeholder{background:#444}.taskboard-task.blocked{background:red;border:1px solid #c00;color:#fff}.taskboard-task.blocked a,.taskboard-task.blocked span{color:#fff}.taskboard-task .taskboard-tagline{border-color:#f1e8cd;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:.6rem}.taskboard-task .taskboard-tag{border-top:.3rem solid #f1e8cd;-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;height:.6rem;z-index:100}.taskboard-task .taskboard-task-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.taskboard-task .taskboard-user-avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:55px}.taskboard-task .taskboard-user-avatar a{display:block;text-align:center}.taskboard-task .taskboard-user-avatar img{margin:0 auto}.taskboard-task .taskboard-user-avatar img:hover{border:2px solid #72a114;-webkit-transition:border .3s linear;transition:border .3s linear}.taskboard-task .taskboard-user-avatar figcaption{color:#e0cd91;display:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.taskboard-task .iocaine img{-webkit-filter:hue-rotate(150deg) saturate(200%);filter:hue-rotate(150deg) saturate(200%)}.taskboard-task .icon-iocaine{background:#000;border-radius:5px;color:#fff;left:.2rem;padding:.1rem;position:absolute;top:1rem}.taskboard-task .task-assigned{color:#e4d6ad;display:block}.taskboard-task .task-num{color:#444;margin-right:.5em}.taskboard-task .taskboard-text{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10;padding:0 .5rem 0 1rem;word-wrap:break-word}.taskboard-task .icon{-webkit-transition:color .3s linear,opacity .3s linear;transition:color .3s linear,opacity .3s linear}.taskboard-task .icon-drag-h,.taskboard-task .icon-edit{bottom:.5rem;color:#f1e8cd;opacity:0;position:absolute}.taskboard-task .icon-drag-h:hover,.taskboard-task .icon-edit:hover{color:#e4d6ad}.taskboard-task .icon-edit{right:1rem}.taskboard-task .icon-drag-h{cursor:move;right:45%}.task-drag{box-shadow:1px 1px 15px 6px rgba(0,0,0,.1)}.kanban-task .avatar a,.kanban-task .task-assigned,.kanban-task .task-text,.kanban-task-maximized .task-archived p,.kanban-task-maximized .task-points,.kanban-task-minimized .task-archived{font-size:.8rem}.kanban-task-minimized .icon-drag-h{font-size:1rem}.kanban-task .icon-drag-h,.kanban-task .icon-edit{font-size:1.2rem}.kanban-task-maximized .icon-drag-h{font-size:2rem}.kanban-task .task-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.kanban-task{background:#fff8e4;cursor:move;margin:.2rem;position:relative}.kanban-task:last-child{margin-bottom:0}.kanban-task:hover .icon-drag-h,.kanban-task:hover .icon-edit{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.kanban-task.ui-sortable-helper{box-shadow:1px 1px 15px rgba(0,0,0,.4);-webkit-transition:box-shadow .3s linear;transition:box-shadow .3s linear}.kanban-task.blocked{background:red;border:1px solid #c00;color:#fff}.kanban-task.blocked a,.kanban-task.blocked span{color:#fff}.kanban-task .kanban-tagline{border-color:#f1e8cd;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:.6rem}.kanban-task .kanban-tag{border-color:#f1e8cd;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;height:.6rem}.kanban-task .kanban-task-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.kanban-task .avatar a{text-align:center}.kanban-task .avatar img{margin:0 auto}.kanban-task .avatar img:hover{border:2px solid #72a114;-webkit-transition:border .3s linear;transition:border .3s linear}.kanban-task .avatar .assigned-to{color:#e0cd91;display:none;overflow:hidden;position:relative;text-overflow:ellipsis;top:-6px;white-space:nowrap;width:50px}.kanban-task .task-assigned{color:#e4d6ad;display:block}.kanban-task .task-text{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10;padding:0 .5rem 0 .8rem;word-wrap:break-word}.kanban-task .task-num{color:#444;margin-right:.3rem}.kanban-task .icon-drag-h,.kanban-task .icon-edit{color:#f1e8cd;opacity:0;position:absolute;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.kanban-task .icon-drag-h:hover,.kanban-task .icon-edit:hover{color:#e0cd91;-webkit-transition:color .3s linear;transition:color .3s linear}.kanban-task-maximized .kanban-task-inner{padding:1rem 1rem 2rem}.kanban-task-maximized .task-archived{background:#e8e8e8;padding:.5rem;text-align:left;-webkit-transition:background .3s linear;transition:background .3s linear}.kanban-task-maximized .task-archived:hover{background:#e1e1e1;-webkit-transition:background .3s linear;transition:background .3s linear}.kanban-task-maximized .task-archived .task-archived-text{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.kanban-task-maximized .task-archived span{color:#b8b8b8}.kanban-task-maximized .task-archived p{color:#b8b8b8;margin:0}.kanban-task-maximized .task-archived p:last-child{color:#555;margin:.5rem 0;text-align:center}.kanban-task-maximized .avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:55px}.kanban-task-maximized .task-name{word-wrap:break-word}.kanban-task-maximized .icon-edit{bottom:.2rem;right:.5rem}.kanban-task-maximized .icon-drag-h{bottom:.2rem;cursor:move;right:45%}.kanban-task-maximized .task-points{color:#e0cd91;margin:0}.kanban-task-maximized .task-points span{display:inline-block}.kanban-task-maximized .task-points span:first-child{padding-right:.2rem}.kanban-task-maximized .kanban-tag{border-top:.3rem solid}.kanban-task-minimized .kanban-task-inner{padding:0 .3rem}.kanban-task-minimized .task-archived{background:#e8e8e8;padding:.3rem;text-align:left}.kanban-task-minimized .task-archived .task-archived-text{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.kanban-task-minimized .task-archived span{color:#b8b8b8}.kanban-task-minimized .task-archived .task-name{display:inline-block;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kanban-task-minimized .task-archived p{color:#b8b8b8;margin:0}.kanban-task-minimized .task-archived p:last-child{display:none}.kanban-task-minimized .avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:55px}.kanban-task-minimized .task-num{vertical-align:top}.kanban-task-minimized .task-name{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:70%}.kanban-task-minimized .task-points{display:none}.kanban-task-minimized .icon-drag-h,.kanban-task-minimized .icon-edit{top:1.4rem}.kanban-task-minimized .icon-edit{bottom:.2rem;right:1rem}.kanban-task-minimized .icon-drag-h{cursor:move;right:.1rem;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.kanban-task-minimized .kanban-tag{border-top:.2rem solid}.notification-light .warning{font-size:1.2rem}.notification-message .warning{font-size:2rem}.notification-message-error .icon-notification-error,.notification-message-success .icon-notification-success{font-size:3rem}.notification-light .warning,.notification-message .warning{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.notification-message{background:rgba(184,184,184,.95);color:#fff;opacity:0;padding:1rem;position:fixed;top:0;-webkit-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%);width:100%;z-index:99920}.notification-message.inactive{-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-message.active{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-message .text{display:inline-block;margin-left:.5rem;width:80%}.notification-message .text p{margin:0}.notification-message .warning{color:#fff;line-height:2.4rem}.notification-message .icon-delete{color:#fff;position:absolute;right:1rem;top:1rem}.notification-message-success{background:rgba(157,206,10,.9)}.notification-message-success .icon-notification-success{display:inline;vertical-align:sub}.notification-message-error{background:rgba(255,0,0,.9)}.notification-message-error .icon-notification-error{display:inline;vertical-align:sub}.notification-light{background:rgba(184,184,184,.95);color:#fff;left:calc(50% - 200px);padding:1rem 1rem .2rem;position:absolute;top:0;-webkit-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%);width:400px;z-index:99999}.notification-light.inactive{-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-light.active{-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-light .text{display:inline-block;margin-left:.5rem;width:80%}.notification-light .warning{color:#fff;line-height:2.4rem}.notification-light .icon-delete{color:#fff;position:absolute;right:1rem}.notification-message-light-error{background:rgba(255,0,0,.95)}.basic-table{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%}.basic-table .row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #ebebeb;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding:.3rem 0;text-align:left;width:100%}.basic-table .row .width-1{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.basic-table .row .width-2{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:2;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2}.basic-table .row .width-3{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.basic-table .row .width-4{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:4;-webkit-flex-grow:4;-ms-flex-positive:4;flex-grow:4}.basic-table .row .width-5{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:5;-webkit-flex-grow:5;-ms-flex-positive:5;flex-grow:5}.basic-table .row .width-6{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6}.basic-table .row .width-7{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:7;-webkit-flex-grow:7;-ms-flex-positive:7;flex-grow:7}.basic-table .row .width-8{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8}.basic-table .row:last-child{border-bottom:0}.paginator{margin:2rem 0}.paginator ul{margin-left:1rem}.paginator li{display:inline-block}.paginator .active span,.paginator .dots,.paginator a{background:#b8b8b8;color:#fff;margin-right:.1rem;padding:.5rem 1rem;-webkit-transition:all .3s linear;transition:all .3s linear}.paginator a:hover{background:#879b89;color:#fff;-webkit-transition:all .3s linear;transition:all .3s linear}.paginator .active span{background:#9dce0a}.paginator .dots{background:0 0;color:#b8b8b8}.v-pagination-list{overflow:hidden}.v-pagination-next,.v-pagination-previous{background-color:#585858;color:#f5f5f5;display:block;padding:.1rem 0;text-align:center;visibility:hidden;width:100%}.v-pagination-next:hover,.v-pagination-previous:hover{background-color:#2c2c2c;-webkit-transition:background .3s linear;transition:background .3s linear}.watchers .watcher-name{font-size:.8rem}.watchers .watchers-header .icon,.watchers .watchers-header .title{font-size:1.2rem}.watchers .watchers-header .title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.watchers{margin-top:1rem}.watchers .watchers-header{border-bottom:2px solid #b8b8b8;padding:.5rem;position:relative}.watchers .watchers-header .title{text-transform:uppercase}.watchers .watchers-header .icon{position:absolute;right:1rem}.watchers .watchers-header.no-watchers{border-bottom:0}.watchers .watcher-single{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:0 0;border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.5rem;vertical-align:middle}.watchers .watcher-single:last-child{border:0}.watchers .watcher-single:hover .icon-delete{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.watchers .watcher-name{color:#444;-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;margin-left:1rem;position:relative}.watchers .watcher-avatar{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.watchers .icon-delete{opacity:0;position:absolute;right:.5rem;top:0;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.watchers .icon-delete:hover{color:red;-webkit-transition:color .3s ease-in;transition:color .3s ease-in}.level{background-color:#b8b8b8;border-radius:9px;height:18px;margin:0 auto;width:18px}.us-created-by .created-by .created-date,.us-created-by .created-by .created-title{font-size:.8rem}.us-created-by .created-by .created-user{font-size:1.2rem}.us-created-by{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:1rem;margin-top:.5rem;position:relative}.us-created-by .user-avatar{-webkit-flex-basis:40px;-ms-flex-preferred-size:40px;flex-basis:40px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.us-created-by .user-avatar img{border-radius:8%;width:100%}.us-created-by .created-by{-webkit-flex-basis:70px;-ms-flex-preferred-size:70px;flex-basis:70px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;margin-left:.5rem}.us-created-by .created-by .created-date,.us-created-by .created-by .created-title{color:#b8b8b8;display:block}.us-created-by .created-by .created-user{color:#72a114;cursor:default}.us-created-by .created-by .created-user.editable{cursor:pointer}.wysiwyg code,.wysiwyg pre{font-size:.8rem}.wysiwyg h2{font-size:1.2rem}.wysiwyg h1{font-size:2rem;font-family:opensans-regular,Arial,Helvetica,sans-serif}.wysiwyg h2,.wysiwyg h3{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.wysiwyg{line-height:1.4rem;overflow:auto}.wysiwyg h1{line-height:2.5rem;text-transform:uppercase}.wysiwyg h2{margin-bottom:.5rem;text-transform:uppercase}.wysiwyg h3{text-transform:uppercase}.wysiwyg ol,.wysiwyg ul{list-style-position:inside;margin-left:1rem}.wysiwyg ul{list-style-type:disc}.wysiwyg dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.wysiwyg dl dd{margin-bottom:16px;padding:0 16px}.wysiwyg a{color:#72a114}.wysiwyg a:hover{color:#9dce0a}.wysiwyg p{line-height:1.4rem;margin-bottom:1rem}.wysiwyg code,.wysiwyg pre{background:#f5f5f5;direction:ltr;font-family:'courier new',monospace;margin-bottom:1rem;unicode-bidi:embed;white-space:pre}.wysiwyg pre{line-height:1.4rem;padding:.5rem}.wysiwyg table{border:1px solid #b8b8b8;margin-bottom:1rem}.wysiwyg table tbody tr:last-child{border-bottom:0}.wysiwyg tr{border-bottom:#b8b8b8 1px solid}.wysiwyg th{border-right:#b8b8b8 1px solid;padding:1rem 1rem 1rem .5rem}.wysiwyg th:last-child{border-right:0}.wysiwyg td{border-right:#b8b8b8 1px solid;padding:.5rem}.wysiwyg td:last-child{border-right:0}.wysiwyg img{max-width:100%}.select-color a{font-size:.8rem}.select-color input{font-size:1rem}.select-color,.select-color input{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.select-color{background:#050505;color:#fff;display:none;left:50px;list-style-type:none;margin:0;position:absolute;top:0;width:323px;z-index:99;border-radius:0 10px 10px 0;padding:15px}.select-color a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.select-color a:last-child{border:0}.select-color a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.select-color:after{background:#050505;content:'';height:15px;left:-7px;position:absolute;top:13px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.select-color li{float:left;margin:0 .5rem .5rem 0}.select-color li:nth-child(7n){margin-right:0}.select-color li:nth-last-child(-n+7){margin-bottom:0}.select-color .color{background-color:#b8b8b8;border-radius:2px;cursor:pointer;height:35px;width:35px}.select-color ul{float:left;margin-bottom:1rem}.select-color input{background-color:#fcfcfc;width:243px}.select-color input::-webkit-input-placeholder{color:#555}.select-color input::-moz-placeholder{color:#555}.select-color input:-moz-placeholder{color:#555}.select-color input:-ms-input-placeholder{color:#555}.select-color .selected-color{background:#b8b8b8;border-radius:2px;cursor:pointer;float:right;height:40px;width:40px}.loader p{font-size:1.2rem}.loader{background-color:#fff;bottom:0;display:none;height:100%;left:0;opacity:0;position:fixed;right:0;top:0;width:100%;z-index:-100}.loader .container{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;width:100%}.loader p{color:#555;text-align:center}.loader.active{background-color:rgba(255,255,255,.95);display:block;opacity:1;z-index:99900}.loading{-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.loading .item{-webkit-animation-duration:5s;animation-duration:5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:loadBar;animation-name:loadBar;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;background:#555;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;height:5px}.loading .item-0{-webkit-animation-delay:0s;animation-delay:0s;background:#bbe831}.loading .item-1{-webkit-animation-delay:1s;animation-delay:1s;background:#237400}.loading .item-2{-webkit-animation-delay:2s;animation-delay:2s;background:#e43050}.loading .item-3{-webkit-animation-delay:3s;animation-delay:3s;background:#810061}.loading .item-4{-webkit-animation-delay:4s;animation-delay:4s;background:#618000}a.help{color:#b8b8b8;position:absolute;right:1rem;top:1rem;-webkit-transition:color .2s linear;transition:color .2s linear}a.help:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.beta{left:0;position:absolute;top:0;z-index:9999}.markItUpHeader ul{background:#f5f5f5;padding:.3rem}.markItUpHeader ul li{display:inline-block;float:none}.markItUpHeader ul li a{opacity:.8}.markItUpHeader ul li a:hover{opacity:.3;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.markItUpHeader ul .preview-icon{position:absolute;right:2.5rem}.markItUpContainer{padding:0}.markdown{position:relative}.preview .actions{background:#f5f5f5;margin-top:.5rem;min-height:2rem;padding:.3rem}a.help-button,a.help-markdown{font-size:.8rem;color:#b8b8b8}a.help-button:hover span,a.help-markdown:hover span{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}a.help-button:hover .icon,a.help-markdown:hover .icon{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}a.help-button .icon,a.help-markdown .icon{color:#b8b8b8;margin-right:.2rem}.duty-assigned-to .assigned-to .assigned-title{font-size:.8rem}.duty-assigned-to .assigned-to .user-assigned{font-size:1.2rem}.duty-assigned-to{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-top:1rem;position:relative}.duty-assigned-to:hover .assigned-to .icon-delete{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.duty-assigned-to.loading{width:100%}.duty-assigned-to.loading span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;font-size:30px;padding:20px 0;text-align:center;width:100%}.duty-assigned-to .user-avatar{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.duty-assigned-to .user-avatar img{border-radius:8%;width:100%}.duty-assigned-to .assigned-to{-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;margin-left:1rem;margin-top:15px}.duty-assigned-to .assigned-to .assigned-title{color:#b8b8b8;display:block}.duty-assigned-to .assigned-to .user-assigned{color:#72a114;cursor:default;line-height:1.5rem}.duty-assigned-to .assigned-to .user-assigned.editable{cursor:pointer}.duty-assigned-to .assigned-to .user-assigned .icon{vertical-align:top}.duty-assigned-to .assigned-to .assigned-name{max-width:80%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block}.duty-assigned-to .assigned-to .icon-delete{color:#b8b8b8;opacity:0;position:absolute;right:0;top:0}.duty-assigned-to .assigned-to .icon-delete:hover{color:red}.user .popover a{font-size:.8rem}.logo-container span,.main-nav a .item{font-size:1.2rem}.main-nav a .icon{font-size:2rem}.menu{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.menu{background-image:url(../images/menu.png);background-position:left bottom;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;height:100%;padding:0 .3rem;position:fixed;text-transform:uppercase;width:90px;z-index:999}.logo-container{cursor:pointer;padding:15px 15px 10px}.logo-container img,.logo-container object,.logo-container svg{height:50px;width:50px}.logo-container span{color:#fff;display:block;margin-top:-5px;text-align:center}.logo-container sup{display:block;line-height:1rem}.main-nav{list-style:none;padding:0;position:relative;text-align:center}.main-nav li{margin-bottom:1rem}.main-nav a{color:#fff;display:block;text-align:center}.main-nav a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.main-nav a span{display:block}.main-nav a .icon{line-height:2.2rem}.main-nav .active{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.user{bottom:1rem;padding:0 10px;position:absolute;width:80px}.user .popover{background:#050505;bottom:0;color:#fff;display:none;left:60px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.user .popover a{border-bottom:1px solid #444;display:block;padding:10px 2px}.user .popover a:last-child{border:0}.user .popover:after{background:#050505;bottom:25px;content:'';height:15px;left:-6px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.user .popover a{color:#fff;text-align:left;text-transform:none}.user .popover a:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.user img{margin:0 5px 10px;width:80%}.user img:hover{border-color:#9dce0a;-webkit-transition:border-color .3s linear;transition:border-color .3s linear}.user .user-settings{position:relative}.user .settings{text-align:center}.user .settings a{color:#f5f5f5;margin-right:.5rem}.user .settings a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.projects-nav-overlay p{font-size:1rem}.projects-list a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.projects-nav-overlay{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover}.projects-nav{background-color:#232323;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100%;left:0;overflow:hidden;padding:2rem 1rem;position:fixed;top:0;-webkit-transform:translate3d(-300px,0,0);transform:translate3d(-300px,0,0);width:300px;z-index:99}.projects-nav form{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.projects-nav h1{color:#fff;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-bottom:2rem;text-align:center}.projects-nav input{background-color:#555;color:#f5f5f5}.projects-nav .icon-search{position:absolute;right:.7rem;top:.7rem}.projects-nav ul{left:0;margin-bottom:0;margin-top:1rem;position:relative;top:0;width:100%}.projects-nav .projects-pagination{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-top:1rem}.projects-nav .create-project-button{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-top:1rem}.projects-nav .create-project-button a{text-align:center;width:100%}.projects-nav .v-pagination-next,.projects-nav .v-pagination-previous{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.projects-list a{color:#f5f5f5;display:block;padding:1rem;position:relative;text-transform:uppercase;width:100%}.projects-list a.active,.projects-list a:hover{background-color:#555;color:#72a114;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.projects-list a.active .icon,.projects-list a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.projects-list a .project-name{display:block;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.projects-list .icon{color:#f5f5f5;opacity:0;position:absolute;right:1rem;top:1rem}.projects-list li{border-bottom:2px solid #555}.projects-nav-overlay{bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;width:100%;z-index:99900}.projects-nav-overlay .container{left:-200px;margin:15% auto 0;opacity:0;position:relative;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);width:150px}.projects-nav-overlay p{color:#9dce0a;padding-top:20px;text-align:center}.lightbox-add-member .help-text,.lightbox-delete-account .newsletter input+label,.lightbox-generic-form .points-per-role .popover a,.lightbox-sprint-add-edit .delete-sprint,.markdown-preview a{font-size:.8rem}.lightbox-generic-form label,.lightbox-select-user .more-watchers,.markdown-preview a{font-size:1rem}.lightbox .close,.lightbox-add-member .icon,.lightbox-ask-choice .subtitle,.lightbox-delete-account .subtitle,.lightbox-delete-project .subtitle,.lightbox-generic-ask .subtitle{font-size:1.2rem}.lightbox-ask-choice .subtitle,.lightbox-delete-account .subtitle,.lightbox-delete-project .subtitle,.lightbox-generic-ask .subtitle,.lightbox-generic-form label,.lightbox-select-user .more-watchers,.markdown-preview a{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.lightbox-delete-account .newsletter input+label,.lightbox-generic-form .points-per-role .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.lightbox{background:rgba(255,255,255,.95);bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;z-index:99910}.lightbox .close{position:absolute;right:2rem;top:2rem}.open.lightbox{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:1;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.close.lightbox{opacity:0;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.lightbox .title{text-align:center}.lightbox input,.lightbox select,.lightbox textarea{margin-bottom:1rem}.lightbox textarea{resize:vertical}.lightbox .button-gray,.lightbox .button-green{display:block;padding:12px;text-align:center}.lightbox-generic-form label,.markdown-preview a{display:inline-block;padding:7px 40px 6px;-webkit-transition:background .3s linear;transition:background .3s linear;text-transform:uppercase}.lightbox-generic-form label:hover,.markdown-preview a:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.lightbox-generic-form label.loading span,.markdown-preview a.loading span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.lightbox-generic-form label .icon,.markdown-preview a .icon{margin-right:.3rem}.markdown-preview{display:inline-block;margin-bottom:.5rem}.markdown-preview a{color:#b8b8b8;padding:3px 20px}.markdown-preview a:first-child{border-right:1px solid #b8b8b8}.markdown-preview a:hover{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}.markdown-preview .active{color:#444}.lightbox-generic-form form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-generic-form fieldset{position:relative}.lightbox-generic-form textarea{margin-bottom:1rem;max-height:9rem;min-height:7rem}.lightbox-generic-form label{border:1px solid #b8b8b8;color:#444;cursor:pointer;display:block;padding:7px 30px;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form label:hover span{color:#fff}.lightbox-generic-form label span{color:#444;vertical-align:middle}.lightbox-generic-form .settings{-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;margin-bottom:1rem}.lightbox-generic-form .settings fieldset{-webkit-flex-basis:30%;-ms-flex-preferred-size:30%;flex-basis:30%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem;text-align:center}.lightbox-generic-form .settings fieldset:last-child{margin:0}.lightbox-generic-form .settings .iocaine:hover,.lightbox-generic-form .settings .requirement:hover{background:#9dce0a;border:1px solid #9dce0a;color:#fff;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form .settings .blocked{padding:8px 30px}.lightbox-generic-form .settings .blocked:hover{background:#ff8282;border:1px solid #ff8282;color:#fff;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form .settings .client-requirement input:checked+label,.lightbox-generic-form .settings .iocaine-flag input:checked+label,.lightbox-generic-form .settings .team-requirement input:checked+label{background:#9dce0a;color:#fff}.lightbox-generic-form .settings .blocking-flag input:checked+label{background:red;color:#fff}.lightbox-generic-form .settings input{display:none}.lightbox-generic-form .points-per-role .popover{background:#050505;color:#fff;display:none;left:35%;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.lightbox-generic-form .points-per-role .popover a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.lightbox-generic-form .points-per-role .popover a:last-child{border:0}.lightbox-generic-form .points-per-role .popover a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-generic-form .points-per-role .popover:after{background:#050505;content:'';height:15px;left:10px;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.lightbox-generic-bulk form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-generic-bulk textarea{margin-bottom:1rem;max-height:12rem;min-height:15rem}.lightbox-search form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-search input{margin-bottom:1rem}.lightbox-add-member .add-member-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:.5rem}.lightbox-add-member .add-member-wrapper:last-child{margin-bottom:0}.lightbox-add-member .add-member-wrapper fieldset{position:relative}.lightbox-add-member .add-member-wrapper fieldset:first-child{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.lightbox-add-member .add-member-wrapper fieldset:last-child{-webkit-flex-basis:200px;-ms-flex-preferred-size:200px;flex-basis:200px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:.5rem}.lightbox-add-member .extra-text{margin-top:1rem}.lightbox-add-member input,.lightbox-add-member select{margin-bottom:0}.lightbox-add-member select{width:80%}.lightbox-add-member .icon{margin-left:.5rem}.lightbox-add-member .icon-delete:hover{color:red}.lightbox-add-member .button{margin-top:1rem}.lightbox-add-member .help-text{padding:.5rem 1rem}.lightbox-add-member .checksley-error-list{right:.5rem}.lightbox-add-member .checksley-error-list li{display:none}.lightbox-add-member .checksley-error-list li:first-child{display:block}.lightbox-sprint-add-edit form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-flex-flow:0;-ms-flex-flow:0;flex-flow:0;max-width:600px}.lightbox-sprint-add-edit .last-sprint-name{color:#555;opacity:1;position:absolute;right:1rem;top:.7rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.lightbox-sprint-add-edit .last-sprint-name.disappear{opacity:0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.lightbox-sprint-add-edit .dates{margin-bottom:1rem}.lightbox-sprint-add-edit .dates div{float:left;margin-right:1%;position:relative;width:49%}.lightbox-sprint-add-edit .dates div:last-child{margin:0;width:50%}.lightbox-sprint-add-edit .delete-sprint{color:#444;display:block;margin-top:1rem;text-align:right}.lightbox-sprint-add-edit .delete-sprint a{color:#b8b8b8;margin-left:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-sprint-add-edit .delete-sprint a:hover{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-generic-ask form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-flex-flow:0;-ms-flex-flow:0;flex-flow:0;max-width:420px}.lightbox-generic-ask .message,.lightbox-generic-ask .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-generic-ask .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-generic-ask .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-generic-ask .options a:first-child{margin-right:.5rem}.lightbox-ask-choice{text-align:center}.lightbox-ask-choice form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.lightbox-ask-choice .question,.lightbox-ask-choice .subtitle{display:block;line-height:1.5rem;text-align:center}.lightbox-ask-choice .replacement,.lightbox-ask-choice .replacement span{display:block}.lightbox-ask-choice .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-ask-choice .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-ask-choice .options a:first-child{margin-right:.5rem}.lightbox-delete-account form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-delete-account .question,.lightbox-delete-account .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-delete-account .newsletter{margin-top:1rem;text-align:center}.lightbox-delete-account .newsletter input{margin-right:.5rem}.lightbox-delete-account .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-delete-account .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-delete-account .options a:first-child{margin-right:.5rem}.lightbox-delete-project form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-delete-project .question,.lightbox-delete-project .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-delete-project .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-delete-project .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-delete-project .options a:first-child{margin-right:.5rem}.lightbox-generic-error section,.lightbox-generic-success section{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-generic-error h2,.lightbox-generic-success h2{line-height:2rem}.lightbox-create-issue form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:600px}.lightbox-create-issue .fieldset-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-create-issue .fieldset-row fieldset{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem;width:30%}.lightbox-create-issue .fieldset-row fieldset:last-child{margin:0}.lightbox-create-issue textarea{margin-bottom:1rem;max-height:12rem;min-height:8rem}.lightbox-block .form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-block textarea{margin-bottom:1rem;max-height:12rem;min-height:8rem}.lightbox-select-user .form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:600px}.lightbox-select-user .watchers{margin-top:1rem;min-height:440px}.lightbox-select-user .watchers .watcher-name{-webkit-box-flex:12;-webkit-flex-grow:12;-ms-flex-positive:12;flex-grow:12}.lightbox-select-user .watcher-single{position:relative}.lightbox-select-user .watcher-single.active,.lightbox-select-user .watcher-single:hover{background:#edfad4;cursor:pointer}.lightbox-select-user .watcher-single:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.lightbox-select-user .watcher-single.active .icon{opacity:1;right:1rem;top:1.3rem}.lightbox-select-user .more-watchers{padding:.5rem;text-align:center}.lb-create-edit-userstory .points-per-role{margin-bottom:1rem}.lb-create-edit-userstory .points-per-role li{margin:.5rem .1rem}.colors-table .table-header{font-size:1rem}.colors-table .icon,.colors-table .icon-check-square{font-size:1.2rem}.colors-table .table-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif;border-bottom:2px solid #b8b8b8}.colors-table .table-header:hover{background:0 0}.colors-table .table-header .row{padding-left:50px}.colors-table .row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1rem}.colors-table .row:hover .options-column{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.colors-table .row.edition,.colors-table .row.new-value{padding-left:50px}.colors-table .row.hidden{display:none}.colors-table .row.edition .current-color{cursor:pointer}.colors-table .row .color-column{-webkit-flex-basis:60px;-ms-flex-preferred-size:60px;flex-basis:60px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100px;position:relative}.colors-table .row .is-archived-column,.colors-table .row .is-closed-column,.colors-table .row .options-column,.colors-table .row .status-wip-limit{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.colors-table .row .status-name{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6;padding:0 10px;position:relative}.colors-table .row .status-name span{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.colors-table .row .status-slug{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6;padding:0 10px}.colors-table .row .options-column{max-width:100px;opacity:0;text-align:right}.colors-table .row .is-archived-column{max-width:130px;padding:0 0 0 10px;text-align:center}.colors-table .row .is-closed-column{max-width:130px;text-align:center}.colors-table .row .status-wip-limit{max-width:130px;padding:0 0 0 10px;text-align:center}.colors-table .row-edit .options-column{opacity:1}.colors-table .table-main{border-bottom:1px solid #b8b8b8}.colors-table .table-main .row:hover{background:#f6fceb;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.colors-table .current-color{background-color:#b8b8b8;border-radius:2px;height:40px;width:40px}.colors-table .icon{color:#b8b8b8;margin-right:1rem}.colors-table .icon:hover{color:#72a114}.colors-table .icon-delete:hover{color:red}.colors-table .icon-check-square{color:#72a114}.category-config .icon{font-size:2rem}.category-config{border-bottom:1px solid #b8b8b8}.category-config:first-child{border-top:1px solid #b8b8b8}.category-config .resume{-webkit-box-align:space-between;-webkit-align-items:space-between;-ms-flex-align:space-between;align-items:space-between;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:1rem;position:relative}.category-config .resume-title{width:280px}.category-config .count{color:#b8b8b8;float:left;padding-right:5px}.category-config .summary-role{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:280px}.category-config .summary-role .role-summary-single{background:#b8b8b8;display:inline-block;height:20px;margin-right:.1rem;width:15px}.category-config .summary-role .role-summary-single.active{background:#72a114}.category-config .summary-role .role-summary-single.inactive{background:#555}.category-config .icon{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;text-align:right}.category-config .category-items{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow-y:hidden;background-color:#f5f5f5;width:100%}.category-config .category-items.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:400px}.category-config .category-items .items-container{padding:1rem}.category-config .category-item{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #fcfcfc;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem .5rem .5rem 2rem}.category-config .category-item:last-child{border-bottom:0}.add-attach span,.more-attachments,.single-attachment{font-size:.8rem}.attachments-header .attachments-title,.single-attachment .editable-attachment-comment{font-size:1rem}.attachments-header .icon,.single-attachment .attachment-settings .editable-settings,.single-attachment .attachment-settings .settings,.single-attachment .icon-delete{font-size:1.2rem}.attachments-header .attachments-title,.single-attachment .attachment-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.attachments{margin-bottom:2rem}.attachments-header{-webkit-align-content:space-between;-ms-flex-line-pack:justify;align-content:space-between;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.attachments-header .attachments-title{color:#444}.attachments-header .attachments-num,.attachments-header .attachments-text{margin-right:.1rem}.attachments-header .icon{color:#444;cursor:pointer}.attachments-header .icon:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.single-attachment{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem 0 .5rem 1rem;position:relative}.single-attachment:hover .attachment-settings .settings{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.single-attachment.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.single-attachment.deprecated,.single-attachment.deprecated .attachment-name a{color:#b8b8b8}.single-attachment.sortable-placeholder{background:#f5f5f5;height:40px}.single-attachment .attachment-name{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-flex-basis:35%;-ms-flex-preferred-size:35%;flex-basis:35%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-right:1rem}.single-attachment .attachment-name .icon{margin-right:.5rem}.single-attachment .attachment-size{color:#b8b8b8;-webkit-flex-basis:15%;-ms-flex-preferred-size:15%;flex-basis:15%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem}.single-attachment .attachment-comments,.single-attachment .editable-attachment-comment{-webkit-flex-basis:35%;-ms-flex-preferred-size:35%;flex-basis:35%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.single-attachment .attachment-comments span,.single-attachment .editable-attachment-comment span{color:#555}.single-attachment .attachment-settings{-webkit-flex-basis:15%;-ms-flex-preferred-size:15%;flex-basis:15%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.single-attachment .attachment-settings .editable-settings,.single-attachment .attachment-settings .settings{color:#b8b8b8;display:block;position:absolute}.single-attachment .attachment-settings .editable-settings:hover,.single-attachment .attachment-settings .settings:hover{color:#72a114}.single-attachment .attachment-settings .settings{opacity:0;top:.5rem}.single-attachment .attachment-settings .editable-settings{opacity:1;top:1rem}.single-attachment .attachment-settings .icon-edit,.single-attachment .attachment-settings .icon-floppy{right:3.5rem}.single-attachment .attachment-settings .icon-delete{right:2rem}.single-attachment .attachment-settings .icon-delete:hover{color:red}.single-attachment .attachment-settings .icon-drag-v{cursor:move;right:0}.single-attachment .icon-delete{color:#b8b8b8}.single-attachment .icon-delete:hover{color:red}.single-attachment .editable-attachment-deprecated{padding-left:1rem}.single-attachment .editable-attachment-deprecated span{color:#b8b8b8}.single-attachment .editable-attachment-deprecated input{margin-right:.2rem;vertical-align:middle}.single-attachment .editable-attachment-deprecated input:checked+span{color:#444}.single-attachment .percentage{background:rgba(114,161,20,.1);bottom:0;height:40px;left:0;position:absolute;top:0;width:45%}.more-attachments{border-bottom:1px solid #b8b8b8;display:block;padding:1rem 0 1rem 1rem}.more-attachments span{color:#b8b8b8}.more-attachments .more-attachments-num{color:#72a114;margin-left:.5rem}.more-attachments:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.add-attach{cursor:pointer;overflow:hidden;position:relative}.add-attach input{display:none}.add-attach span{color:#b8b8b8}.related-tasks-body .pop-status a,.related-tasks-body .row{font-size:.8rem}.related-tasks-body .task-name input,.related-tasks-header .related-tasks-title{font-size:1rem}.related-tasks-body .iocaine .icon-iocaine,.related-tasks-body .iocaine:hover .icon-iocaine,.related-tasks-body .task-settings a,.related-tasks-header .icon{font-size:1.2rem}.related-tasks-body .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.related-tasks-header .related-tasks-title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.related-tasks{margin-bottom:2rem;position:relative}.related-tasks-header{-webkit-align-content:space-between;-ms-flex-line-pack:justify;align-content:space-between;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.related-tasks-header .icon{color:#444;cursor:pointer}.related-tasks-header .icon:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.related-tasks-body{width:100%}.related-tasks-body .row{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.5rem 0 .5rem .5rem;position:relative;text-align:left;width:100%}.related-tasks-body .row:hover{background:0 0}.related-tasks-body .row:hover .task-settings{opacity:1;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .row:last-child{border:0}.related-tasks-body .row .tasks{-webkit-flex-basis:78%;-ms-flex-preferred-size:78%;flex-basis:78%;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10}.related-tasks-body .row .assigned-to,.related-tasks-body .row .status{-webkit-flex-basis:10%;-ms-flex-preferred-size:10%;flex-basis:10%}.related-tasks-body .related-task-create-form{padding:0}.related-tasks-body .related-task-create-form.active{padding:.5rem 0 .5rem .5rem}.related-tasks-body .status{position:relative;text-align:left}.related-tasks-body .status:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.related-tasks-body .status .not-clickable:hover{color:#444}.related-tasks-body .status .popover a{text-align:left;width:100%}.related-tasks-body .status .popover .point{text-align:center}.related-tasks-body .status .icon{color:#b8b8b8;margin-left:.2rem;opacity:0}.related-tasks-body .pop-status{background:#050505;color:#fff;display:none;left:40%;list-style-type:none;margin:0;padding:10px 1rem 10px 10px;position:absolute;top:0;width:200px;z-index:99}.related-tasks-body .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.related-tasks-body .pop-status a:last-child{border:0}.related-tasks-body .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.related-tasks-body .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.related-tasks-body .pop-status.fix{bottom:0;top:auto}.related-tasks-body .task-name{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative}.related-tasks-body .task-name a{display:inline-block;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.related-tasks-body .task-name input{margin-right:1rem;padding:3px;width:85%}.related-tasks-body .task-name.loading{margin:0;padding:8px;text-align:center;width:100%}.related-tasks-body .task-name.loading span{-webkit-animation:loading .5s linear,spin 1s linear infinite;animation:loading .5s linear,spin 1s linear infinite}.related-tasks-body .blocked,.related-tasks-body .blocked:hover{background:#ff8282;color:#fff}.related-tasks-body .blocked a,.related-tasks-body .blocked:hover a{color:#fff!important}.related-tasks-body .blocked .icon,.related-tasks-body .blocked .icon:hover,.related-tasks-body .blocked a:hover,.related-tasks-body .blocked:hover .icon,.related-tasks-body .blocked:hover .icon:hover,.related-tasks-body .blocked:hover a:hover{color:#fff}.related-tasks-body .icon-iocaine{display:none}.related-tasks-body .iocaine,.related-tasks-body .iocaine:hover{background:rgba(157,206,10,.3)}.related-tasks-body .iocaine .icon-iocaine,.related-tasks-body .iocaine:hover .icon-iocaine{display:inline-block;margin-right:.5rem;vertical-align:top}.related-tasks-body .task-settings{margin:0 0 0 2rem;opacity:0;position:absolute;right:0;top:.1rem;width:10%}.related-tasks-body .task-settings a{color:#b8b8b8;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .task-settings a:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .assigned-to{position:relative;text-align:left}.related-tasks-body .task-assignedto{position:relative}.related-tasks-body .task-assignedto.editable{cursor:pointer}.related-tasks-body .task-assignedto:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.related-tasks-body .task-assignedto figcaption{max-width:50%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.related-tasks-body .task-assignedto .icon{opacity:0;position:absolute;right:.5rem;top:.5rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.related-tasks-body .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.related-tasks-body .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px;height:35px;width:35px}.related-tasks-body .avatar figcaption{margin-left:.5rem}.activity-single .comment-restore,.activity-single .date,.activity-single .deleted-comment,.activity-single.deleted-comment,.change-entry .activity-fromto,.more-activity,.more-comments,.show-more-comments{font-size:.8rem}.activity-single .deleted-comment .comment-body p,.activity-single.deleted-comment .comment-body p{font-size:1rem}.history-tabs li{font-size:1.2rem}.history-tabs{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.change-entry .activity-changed{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.history{margin-bottom:1rem}.changes-title{display:block;padding:.5rem}.changes-title:hover .icon{color:#72a114;-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear}.changes-title .icon{color:#444;float:right;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.change-entry{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.change-entry:last-child{border-bottom:0}.change-entry .activity-changed,.change-entry .activity-fromto{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.history-tabs{border-bottom:3px solid #b8b8b8;padding:.5rem 0}.history-tabs li{display:inline-block}.history-tabs li:first-child{border-right:1px solid #b8b8b8}.history-tabs a{color:#b8b8b8;padding:0 2rem;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.history-tabs a.active{color:#444}.history-tabs a:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.history-tabs .icon{margin-right:.5rem}.add-comment:after{clear:both;content:'';display:table}.add-comment.active .button-green{display:block}.add-comment.active textarea{height:6rem;-webkit-transition:height .3s ease-in;transition:height .3s ease-in}.add-comment.active .help-markdown{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.add-comment.active .preview-icon{opacity:1;position:absolute;right:1rem}.add-comment textarea{background:#fff;height:5rem;margin-bottom:.5rem;min-height:41px}.add-comment .help-markdown{opacity:0}.add-comment .save-comment{color:#fff;float:right}.add-comment .button-green{display:none}.add-comment .edit,.add-comment .preview-icon{position:absolute;right:1rem}.add-comment .preview-icon{opacity:0}.show-more-comments{border-bottom:1px solid #b8b8b8;border-top:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem 0 1rem 1rem}.show-more-comments:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.more-comments{border-bottom:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem}.more-comments .prev-comments-num{color:#72a114;margin-left:.5rem}.comment-list.activeanimation .comment-single.ng-enter:last-child,.comment-list.activeanimation .comment-single.ng-leave:last-child{-webkit-transition:all .3s ease-in;transition:all .3s ease-in}.comment-list.activeanimation .comment-single.ng-enter:last-child,.comment-list.activeanimation .comment-single.ng-leave.ng-leave-active:last-child{opacity:0}.comment-list.activeanimation .comment-single.ng-enter.ng-enter-active:last-child,.comment-list.activeanimation .comment-single.ng-leave:last-child{opacity:1}.activity-single{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:2rem 0;position:relative}.activity-single:hover .comment-delete,.activity-single:hover .comment-restore{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.activity-single:first-child{margin-top:0}.activity-single:last-child{border-bottom:0}.activity-single .deleted-comment,.activity-single.deleted-comment{color:#b8b8b8;padding:.5rem}.activity-single .deleted-comment a,.activity-single.deleted-comment a{color:#b8b8b8;margin-left:.3rem}.activity-single .deleted-comment a:hover,.activity-single.deleted-comment a:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single .deleted-comment img,.activity-single.deleted-comment img{-webkit-filter:grayscale(100%);filter:grayscale(100%);opacity:.5}.activity-single .deleted-comment .comment-body,.activity-single.deleted-comment .comment-body{display:none;margin:.2rem 0 .5rem}.activity-single .comment-restore{color:#b8b8b8;position:absolute;right:0;top:.4rem}.activity-single .comment-restore .icon{vertical-align:baseline}.activity-single .comment-restore:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single .username{color:#72a114;margin-bottom:.5rem}.activity-single .activity-user{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.activity-single .activity-user img{max-width:70px;width:100%}.activity-single .activity-username{color:#72a114;margin-bottom:.5rem}.activity-single .activity-content{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:20;-webkit-flex-grow:20;-ms-flex-positive:20;flex-grow:20}.activity-single .changes{background:#f5f5f5}.activity-single .changes .change-entry{display:none}.activity-single .changes .change-entry.active{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.activity-single .date{color:#b8b8b8;margin-left:1rem}.activity-single .wysiwyg{margin-bottom:0}.activity-single .comment-delete{color:red;opacity:0;position:absolute;right:0;top:2rem;-webkit-transition:all .2s linear;transition:all .2s linear}.activity-single .comment-delete:hover{color:#ff8282;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single.activity .change-entry{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.more-activity{border-bottom:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem}.more-activity .prev-activity-num{color:#72a114;margin-left:.5rem}.wizard-create-project p{font-size:.8rem}.wizard-create-project .close{font-size:1.2rem}.wizard-create-project .create-step1 input+label .icon{font-size:3rem}.wizard-create-project{bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;z-index:99910}.wizard-create-project .close{position:absolute;right:2rem;top:2rem}.open.wizard-create-project{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:1;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.close.wizard-create-project{opacity:0;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.wizard-create-project .title{text-align:center}.wizard-create-project input,.wizard-create-project select,.wizard-create-project textarea{margin-bottom:1rem}.wizard-create-project textarea{resize:vertical}.wizard-create-project .button-gray,.wizard-create-project .button-green{display:block;padding:12px;text-align:center}.wizard-create-project{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;color:#fff;text-align:center}.wizard-create-project form{width:500px}.wizard-create-project .title{width:100%}.wizard-create-project h1,.wizard-create-project p{color:#fff}.wizard-create-project h1{line-height:1.5rem}.wizard-create-project p{opacity:.8}.wizard-create-project input,.wizard-create-project select,.wizard-create-project textarea{background:rgba(255,255,255,.7)}.wizard-create-project input::-webkit-input-placeholder,.wizard-create-project select::-webkit-input-placeholder,.wizard-create-project textarea::-webkit-input-placeholder{color:#444}.wizard-create-project input::-moz-placeholder,.wizard-create-project select::-moz-placeholder,.wizard-create-project textarea::-moz-placeholder{color:#444}.wizard-create-project input:-moz-placeholder,.wizard-create-project select:-moz-placeholder,.wizard-create-project textarea:-moz-placeholder{color:#444}.wizard-create-project input:-ms-input-placeholder,.wizard-create-project select:-ms-input-placeholder,.wizard-create-project textarea:-ms-input-placeholder{color:#444}.wizard-create-project .close{color:#fff}.wizard-create-project .close:hover{color:#ff8282}.wizard-create-project .wizard-step{-webkit-animation:formSlide .4s ease-in-out;animation:formSlide .4s ease-in-out;-webkit-animation-direction:alternate-reverse;animation-direction:alternate-reverse;display:none}.wizard-create-project .wizard-step.active{-webkit-animation:formSlide .4s ease-in-out;animation:formSlide .4s ease-in-out}.wizard-create-project .wizard-step.active.create-step1,.wizard-create-project .wizard-step.active.create-step2,.wizard-create-project .wizard-step.active.create-step3{display:block}.wizard-create-project .wizard-action div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.wizard-create-project .wizard-action a{color:#fff;display:inline-block;-webkit-flex-basis:40%;-ms-flex-preferred-size:40%;flex-basis:40%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.wizard-create-project .wizard-action a:first-child{margin-right:.5rem}.wizard-create-project .create-step1 .template-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.wizard-create-project .create-step1 fieldset{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.wizard-create-project .create-step1 fieldset:first-child{margin-right:.5rem}.wizard-create-project .create-step1 input{display:none}.wizard-create-project .create-step1 input:checked+label{background:rgba(157,206,10,.7);-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label{background:rgba(245,245,245,.7);cursor:pointer;display:block;margin-bottom:1rem;padding:1rem;text-align:center;-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label:hover{background:rgba(114,161,20,.7);-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label .icon{color:#fff}.wizard-create-project .create-step1 h2{color:#fff;margin:.5rem 0 0;text-transform:uppercase}.wizard-create-project .create-step1 p{text-align:center}.wizard-create-project .progress-bar{bottom:0;height:.5rem;left:0;position:absolute;width:100%}.wizard-create-project .step1 .bar{-webkit-transition:width .6s ease-in-out;transition:width .6s ease-in-out;width:25%}.wizard-create-project .step1 .progress-state span:nth-child(1){color:#fff;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out;-webkit-transition-delay:.6s;transition-delay:.6s}.wizard-create-project .step2 .bar{-webkit-transition:width .6s ease-in-out;transition:width .6s ease-in-out;width:75%}.wizard-create-project .step2 .progress-state span:nth-child(1),.wizard-create-project .step2 .progress-state span:nth-child(2){color:#fff;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out;-webkit-transition-delay:.6s;transition-delay:.6s}.wizard-create-project .progress-state{position:absolute;width:100%}.wizard-create-project .progress-state span{color:rgba(255,255,255,.5);display:inline-block;margin-left:-100px;position:absolute;text-align:center;top:-2rem;-webkit-transition:all 1s ease-in;transition:all 1s ease-in;width:200px}.wizard-create-project .progress-state span:nth-child(1){left:25%}.wizard-create-project .progress-state span:nth-child(2){left:75%}.wizard-create-project .progress-bar-wrapper{background:rgba(255,255,255,.3);height:.5rem}.wizard-create-project .bar{background:rgba(157,206,10,.9);height:.5rem;left:0;position:absolute;top:0;width:0}.external-reference{font-size:.8rem}.blocked .external-reference{color:#fff}.blocked .external-reference a{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.blocked .external-reference a:hover{color:#ff8282}.external-reference{color:#b8b8b8;margin-top:.5rem}.external-reference a{border-left:1px solid #b8b8b8;padding:0 .2rem;-webkit-transition:color .3s linear;transition:color .3s linear}.external-reference a:hover{color:#72a114}.external-reference a:first-child{border:0}.home-project .welcome-user .logout,.home-projects-list .welcome-user .logout,.project-content p{font-size:.8rem}.all-projects li a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.home-project,.home-projects-list{background:url(/images/invitation_bg.jpg) center center no-repeat #000;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-size:cover;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;padding:0;position:fixed;top:0;width:100%}.home-project .welcome-user,.home-projects-list .welcome-user{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:absolute;right:1rem;top:1rem}.home-project .welcome-user p,.home-projects-list .welcome-user p{color:#f5f5f5;margin-bottom:0}.home-project .welcome-user p span:before,.home-projects-list .welcome-user p span:before{content:' '}.home-project .welcome-user .logout,.home-projects-list .welcome-user .logout{float:right}.home-project .welcome-user .logout:hover,.home-projects-list .welcome-user .logout:hover{color:#ff8282}.home-project .welcome-user .info,.home-projects-list .welcome-user .info{padding-right:1rem}.home-project .welcome-user img,.home-projects-list .welcome-user img{width:40px}.home-projects-wrapper{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:1200px}.home-projects-list-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.recent-projects{-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;max-width:800px}.recent-projects ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0}.recent-projects a{height:100%;left:0;padding:1rem;position:absolute;top:0;width:100%}.recent-projects li{background-color:rgba(255,255,255,.5);color:#f5f5f5;-webkit-flex-basis:230px;-ms-flex-preferred-size:230px;flex-basis:230px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;height:130px;margin-bottom:1rem;margin-right:1rem;overflow:hidden;position:relative;-webkit-transition:background-color .3s linear;transition:background-color .3s linear;width:23.5%}.recent-projects li:hover{background-color:rgba(157,206,10,.5);cursor:pointer;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.recent-projects li:hover p{color:#b8b8b8;-webkit-transition:color .3s linear;transition:color .3s linear}.recent-projects h2{color:#f5f5f5;line-height:2rem}.recent-projects p{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.project-content h2{margin-bottom:.5rem}.project-content p{line-height:1rem}.all-projects{background-color:rgba(0,0,0,.5);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:1rem;max-height:422px;padding:1rem;width:285px}.all-projects h1{color:#f5f5f5;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;text-align:center}.all-projects .v-pagination-list{max-height:221px}.all-projects ul{left:0;margin-bottom:0;position:relative;top:0;width:100%}.all-projects li{border-bottom:2px solid #555}.all-projects li a{color:#f5f5f5;display:block;padding:1rem;text-transform:uppercase;width:100%}.all-projects li .active,.all-projects li a:hover{background-color:#555;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.all-projects .projects-pagination{width:100%}.all-projects .create-project-button-wrapper{position:relative;width:100%}.all-projects .button-green{color:#f5f5f5;text-align:center;width:100%}.all-projects .button-green:hover{color:#f5f5f5}.all-projects .v-pagination-next{margin-bottom:1rem}.home-project-info-list .info-text{font-size:.8rem}.home-project-info-list .info-num{font-size:2rem;font-family:opensans-semibold,Arial,Helvetica,sans-serif}.home-project-info-list{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.home-project-info-list li{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:1rem}.home-project-info-list .info-num{float:left;margin-right:.3rem;position:relative;top:5px}.home-project-info-list .info-text{float:left;line-height:.9rem}.project-data-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.project-data-container p{-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.project-data-container ul{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-data-container li{display:inline-block;margin-right:.1rem;width:10%}.project-data-container li figure{width:100%}.create-project .tagline{font-size:2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.create-project{background:url(/images/bg.png) center center no-repeat;background-size:cover;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.create-project fieldset{margin-bottom:1rem}.create-project .create-project-container{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.create-project h1{color:#fff;text-align:center}.create-project .logo,.create-project .tagline{margin-bottom:1rem;text-align:center}.create-project .tagline{color:#fff;line-height:2rem;text-transform:uppercase}.create-project form{margin-bottom:2rem}.create-project input{background:#fff}.create-project input::-webkit-input-placeholder{color:#b8b8b8}.create-project input::-moz-placeholder{color:#b8b8b8}.create-project input:-moz-placeholder{color:#b8b8b8}.create-project input:-ms-input-placeholder{color:#b8b8b8}.create-project .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center}.create-project .button:hover{background:#9dce0a}.create-project a:hover{color:#fff}.issues-table .pop-status a,.issues-table .table-main{font-size:.8rem}.issues-table .title{font-size:1rem}.issues-table .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.issues-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.issues-table{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:2rem}.issues-table.empty{display:none}.issues-table .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.issues-table .row .icon{display:inline}.issues-table .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.issues-table .title{border-bottom:1px solid #b8b8b8}.issues-table .title:hover{background:0 0}.issues-table .title div{cursor:pointer}.issues-table .table-main{border-bottom:1px solid #ebebeb}.issues-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.issues-table .avatar img{width:35px}.issues-table .avatar figcaption{-webkit-flex-basis:60%;-ms-flex-preferred-size:60%;flex-basis:60%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:.5rem}.issues-table .level-field{-webkit-flex-basis:70px;-ms-flex-preferred-size:70px;flex-basis:70px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.issues-table .subject{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:7;-webkit-flex-grow:7;-ms-flex-positive:7;flex-grow:7;padding-right:1rem}.issues-table .subject span:first-child{margin-right:.5rem}.issues-table .assigned-field,.issues-table .created-field,.issues-table .issue-field{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem;position:relative;text-align:left}.issues-table .assigned-field{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:2;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2}.issues-table .issue-assignedto{cursor:pointer;position:relative}.issues-table .issue-assignedto:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.issues-table .issue-assignedto figcaption{max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.issues-table .issue-assignedto .icon{opacity:0;position:absolute;right:0;top:.5rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.issues-table .pop-status{background:#050505;color:#fff;display:none;left:0;list-style-type:none;margin:0;padding:10px;position:absolute;top:20px;width:200px;z-index:99}.issues-table .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.issues-table .pop-status a:last-child{border:0}.issues-table .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.issues-table .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.issues-table .pop-status.fix{bottom:0;top:auto}.kanban-table-body .task-column .kanban-column-intro{font-size:.8rem}.kanban-table-body,.kanban-table-header .task-colum-name .icon{font-size:1rem}.kanban-table-header .task-colum-name{font-size:1.2rem}.kanban-table-body .task-column .kanban-column-intro{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.kanban-table{overflow:hidden;width:100%}.kanban-table .vfold.task-colum-name{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:.8;padding:.5rem 0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.kanban-table .vfold.task-colum-name .icon-bulk,.kanban-table .vfold.task-colum-name .icon-closed-eye,.kanban-table .vfold.task-colum-name .icon-open-eye,.kanban-table .vfold.task-colum-name .icon-plus,.kanban-table .vfold.task-colum-name .icon-vfold,.kanban-table .vfold.task-colum-name .icon-vunfold,.kanban-table .vfold.task-colum-name span{display:none}.kanban-table .vfold.task-colum-name .hunfold{margin:0}.kanban-table .vfold.task-colum-name,.kanban-table .vfold.task-column{-webkit-flex-flow:1;-ms-flex-flow:1;flex-flow:1;max-width:30px;min-height:2.5rem;min-width:30px;width:30px}.kanban-table .vfold .kanban-task{display:none}.kanban-table-header{margin-bottom:.5rem;position:relative;width:100%}.kanban-table-header .kanban-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;position:absolute}.kanban-table-header .task-colum-name{background:#f5f5f5;border-top:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin:0 10px 0 0;max-width:300px;padding:.5rem .5rem .5rem 1rem;position:relative;text-transform:uppercase}.kanban-table-header .task-colum-name:last-child{margin-right:0}.kanban-table-header .task-colum-name .icon{color:#b8b8b8;margin-right:.3rem;-webkit-transition:color .2s linear;transition:color .2s linear}.kanban-table-header .task-colum-name .icon:hover{color:#72a114}.kanban-table-header .task-colum-name .icon.hfold,.kanban-table-header .task-colum-name .icon.hunfold{display:inline-block;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.kanban-table-body{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;overflow-x:auto;width:100%}.kanban-table-body .task-column{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 10px 0 0;max-width:300px;overflow-y:auto}.kanban-table-body .task-column:last-child{margin-right:0}.kanban-table-body .task-column .kanban-column-intro{color:#b8b8b8;margin:1rem 2rem}.kanban-table-body .task-column .kanban-column-intro.active{color:#050505}.kanban-table-body .task-column .kanban-wip-limit{background:red;border-radius:2px;height:4px;margin:.5rem 0;padding:0}.kanban-table-body .kanban-uses-box{background:#f5f5f5}.kanban-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.search-filter a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.search-filter ul{border-bottom:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-bottom:.5rem}.search-filter li{margin-right:1rem}.search-filter a{opacity:.2}.search-filter .active,.search-filter a:hover{color:#555;opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.search-filter .icon{margin-right:.4rem}.search-filter .name{padding-left:5px}.search-result-table .table-main{font-size:.8rem}.search-result-table .title,.search-result-table .user-story-name .icon{font-size:1rem}.search-result-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.search-result-table .empty .title{border:0}.search-result-table .row{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.search-result-table .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.search-result-table .row .user-stories{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:5;-webkit-flex-grow:5;-ms-flex-positive:5;flex-grow:5;-webkit-flex-shrink:1;-ms-flex-negative:1;flex-shrink:1}.search-result-table .row .points,.search-result-table .row .status{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem;text-align:center}.search-result-table .row .assigned-to{-webkit-flex-basis:250px;-ms-flex-preferred-size:250px;flex-basis:250px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem}.search-result-table .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.search-result-table .user-story-name input{vertical-align:top}.search-result-table .user-story-name span{display:inline-block;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-result-table .user-story-name .icon{color:#b8b8b8}.search-result-table .user-story-name .icon:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.search-result-table .title{border-bottom:1px solid #b8b8b8}.search-result-table .title:hover{background:0 0}.search-result-table .table-main{border-bottom:1px solid #f5f5f5}.search-result-table .points,.search-result-table .status{position:relative}.search-result-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.search-result-table .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px}.search-result-table .avatar figcaption{display:inline-block;margin-left:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-in input{background:#444;color:#fff}.search-in input::-webkit-input-placeholder{color:#b8b8b8}.search-in input::-moz-placeholder{color:#b8b8b8}.search-in input:-moz-placeholder{color:#b8b8b8}.search-in input:-ms-input-placeholder{color:#b8b8b8}.search-in .icon-search{color:#b8b8b8;position:absolute;right:.7rem;top:.7rem}.filters h2 .icon-arrow-right{font-size:1rem}.filters h2{font-size:1.2rem}.filters h1{vertical-align:baseline}.filters h1 .icon{margin:0}.filters h1 a{vertical-align:baseline}.filters h2{margin-top:1rem}.filters h2 .icon-arrow-right{vertical-align:middle}.filters input{background:#444;color:#fff}.filters input::-webkit-input-placeholder{color:#b8b8b8}.filters input::-moz-placeholder{color:#b8b8b8}.filters input:-moz-placeholder{color:#b8b8b8}.filters input:-ms-input-placeholder{color:#b8b8b8}.filters .icon-search{color:#b8b8b8;position:absolute;right:.7rem;top:.7rem}.filters-inner{opacity:0;-webkit-transition:all .1s ease-in;transition:all .1s ease-in}.filters-inner .loading{background:#444;border:1px solid #b8b8b8;display:inline-block;margin:0;padding:8px;text-align:center;width:100%}.filters-inner .loading .icon-spinner{color:#f5f5f5;float:none}.filters-inner .loading span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.filters-applied{margin-top:.5rem}.filters-applied .single-filter{margin-bottom:.5rem}.filters-step-cat .save-filters{color:#fff;display:block;text-align:center}.filters-step-cat .my-filter-name{background:#444;color:#f5f5f5;width:100%}.filters-step-cat .my-filter-name::-webkit-input-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name::-moz-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name:-moz-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name:-ms-input-placeholder{color:#b8b8b8}.filters-cats{margin-top:2rem}.filters-cats li{border-bottom:1px solid #b8b8b8;text-transform:uppercase}.filters-cats .custom-filters .title{color:#72a114}.filters-cats a{color:#444;display:block;padding:.5rem 0 .5rem .5rem;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.filters-cats a:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.filters-cats a:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.filters-cats .icon{color:#444;float:right;opacity:0;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.list-filters li a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.list-filters{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-color:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:2rem;padding:.5rem 1rem}.list-filters ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:0}.list-filters li{margin-right:2rem}.list-filters li a{opacity:.4}.list-filters li .active,.list-filters li a:hover{color:#050505;opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.list-filters li .icon{padding-right:.5rem}.filter-tags{margin-top:2rem}.filter-tags .filter-tag{color:#fff;cursor:pointer;margin-bottom:1rem;opacity:.5;padding:.5rem 1rem;position:relative}.filter-tags .filter-tag.active{opacity:1}.filter-tags .tag-count{background:rgba(0,0,0,.3);padding:.5rem 1rem;position:absolute;right:0;top:0}.sprints .sprint .description{font-size:.5rem}.sprints .filter-closed-sprints,.sprints .sprint-table .column-us,.sprints .us-item-row .user-story-name{font-size:.8rem}.sprints .sprint .number,.sprints .sprint .sprint-date,.sprints .sprint-name a{font-size:1.2rem}.sprints .sprint .sprint-date,.sprints .sprint-name a{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.sprints .summary{background:#b8b8b8}.sprints .summary:after{clear:both;content:'';display:table}.sprints .summary ul{width:40%}.sprints .summary li{color:#444}.sprints .new-sprint{float:right}.sprints .new-sprint .button{padding:.5rem 1.5rem}.sprints .filter-closed-sprints{display:block;padding-bottom:1rem;text-align:center}.sprints .filter-closed-sprints .icon-kanban{margin-right:.3rem;vertical-align:middle}.sprints .filter-closed-sprints .load{display:inline-block;margin-left:.3rem;vertical-align:middle}.sprints .sprint-name a{max-width:90%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;margin-right:3px}.sprints .sprint{margin-bottom:2rem;overflow:hidden}.sprints .sprint header{position:relative}.sprints .sprint:hover .icon-edit{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.sprints .sprint .icon{display:inline-block}.sprints .sprint .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprints .sprint .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprints .sprint .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprints .sprint .icon-edit{color:#b8b8b8;opacity:0;position:absolute;right:0;top:0;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in;vertical-align:baseline}.sprints .sprint .icon-edit:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.sprints .sprint .description{line-height:.6rem;margin-top:5px}.sprints .sprint .sprint-summary{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.sprints .sprint .sprint-date{color:#b8b8b8;-webkit-flex-flow:1;-ms-flex-flow:1;flex-flow:1}.sprints .sprint .sprint-points{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.sprints .sprint ul{float:right;margin:0}.sprints .sprint li{display:inline-block}.sprints .sprint li:first-child{margin-right:3px}.sprints .sprint-progress-bar{background:#b8b8b8;border-radius:2px;height:8px;margin-bottom:1rem;margin-top:.5rem;position:relative;width:100%}.sprints .sprint-progress-bar .current-progress{background:#72a114;border-radius:2px;height:8px;left:0;position:absolute;top:0;width:calc(30% - 4px)}.sprints .sprint-table .row{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5em 0;text-align:left;width:100%}.sprints .sprint-table .row:hover{background:#d7d7d7;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.sprints .sprint-table .row:last-child{border-bottom:0}.sprints .sprint-table .row.sortable-placeholder{background:#d7d7d7;height:40px}.sprints .sprint-table .row.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.sprints .sprint-table .column-us{-webkit-flex-flow:3;-ms-flex-flow:3;flex-flow:3;padding:0 4px}.sprints .sprint-table .us-name{max-width:250px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.sprints .sprint-table .us-name.closed{color:#c5c5c5}.sprints .sprint-table .us-name.blocked{color:red}.sprints .sprint-table .column-points{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 4px;text-align:right}.sprints .sprint-table .column-points.closed{color:#c5c5c5}.sprints .sprint-table .column-points.blocked{color:red}.sprints .button-gray{display:block;margin-top:1rem;text-align:center}.sprints .us-item-row .icon-drag-v,.sprints .us-item-row .popover,.sprints .us-item-row .status,.sprints .us-item-row .tags-block,.sprints .us-item-row .us-settings,.sprints .us-item-row input{display:none}.sprints .us-item-row .user-story-name{line-height:1rem;margin-top:5px}.sprint-old-open .sprint-name .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprint-old-open .sprint-name .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprint-old-open .sprint-name .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprint-closed .sprint-table{display:none}.sprint-closed .sprint-name .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprint-closed .sprint-name .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprint-closed .sprint-name .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprint-closed .description,.sprint-closed .number{color:#b8b8b8}.sprint-closed .sprint-progress-bar .current-progress{background:#9f9f9f}.sprint-closed .button-gray{background:#b8b8b8}.burndown{margin-bottom:2rem;width:100%}.backlog-table-body .doom-line span,.backlog-table-body .pop-points a,.backlog-table-body .pop-points-open a,.backlog-table-body .pop-role a,.backlog-table-body .pop-status a,.backlog-table-body .row,.backlog-table-body .tags-block .tag,.backlog-table-header .pop-points a,.backlog-table-header .pop-points-open a,.backlog-table-header .pop-role a,.backlog-table-header .pop-status a,.backlog-table-header .row{font-size:.8rem}.backlog-table-header .backlog-table-title{font-size:1rem}.backlog-table-body .icon-drag-v,.backlog-table-body .us-settings a{font-size:1.2rem}.backlog-table-body .doom-line span{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.backlog-table-body .pop-points,.backlog-table-body .pop-points-open,.backlog-table-body .pop-role,.backlog-table-body .pop-status,.backlog-table-header .pop-points,.backlog-table-header .pop-points-open,.backlog-table-header .pop-role,.backlog-table-header .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.backlog-table-header .backlog-table-title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.backlog-table-body,.backlog-table-header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%}.backlog-table-body.show-tags .tags-block,.backlog-table-header.show-tags .tags-block{display:block}.backlog-table-body .row,.backlog-table-header .row{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem 0 .5rem .5rem;text-align:left;width:100%}.backlog-table-body .backlog-table-subtitle:hover,.backlog-table-body .backlog-table-title:hover,.backlog-table-body .row:hover,.backlog-table-header .backlog-table-subtitle:hover,.backlog-table-header .backlog-table-title:hover,.backlog-table-header .row:hover{background:0 0}.backlog-table-body .backlog-table-subtitle .user-stories,.backlog-table-body .backlog-table-title .user-stories,.backlog-table-body .row .user-stories,.backlog-table-header .backlog-table-subtitle .user-stories,.backlog-table-header .backlog-table-title .user-stories,.backlog-table-header .row .user-stories{width:100%}.backlog-table-body .backlog-table-subtitle .status,.backlog-table-body .backlog-table-title .status,.backlog-table-body .row .status,.backlog-table-header .backlog-table-subtitle .status,.backlog-table-header .backlog-table-title .status,.backlog-table-header .row .status{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.backlog-table-body .backlog-table-subtitle .points,.backlog-table-body .backlog-table-title .points,.backlog-table-body .row .points,.backlog-table-header .backlog-table-subtitle .points,.backlog-table-header .backlog-table-title .points,.backlog-table-header .row .points{-webkit-flex-basis:125px;-ms-flex-preferred-size:125px;flex-basis:125px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.backlog-table-body .points,.backlog-table-body .status,.backlog-table-header .points,.backlog-table-header .status{position:relative;text-align:right}.backlog-table-body .points .popover a,.backlog-table-body .status .popover a,.backlog-table-header .points .popover a,.backlog-table-header .status .popover a{text-align:left;width:100%}.backlog-table-body .points .popover .point,.backlog-table-body .status .popover .point,.backlog-table-header .points .popover .point,.backlog-table-header .status .popover .point{text-align:center}.backlog-table-body .points .icon,.backlog-table-body .status .icon,.backlog-table-header .points .icon,.backlog-table-header .status .icon{color:#b8b8b8;margin-left:.2rem}.backlog-table-body .pop-status,.backlog-table-header .pop-status{background:#050505;color:#fff;display:none;left:65%;list-style-type:none;margin:0;padding:10px 1rem 10px 10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-status a,.backlog-table-header .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-status a:last-child,.backlog-table-header .pop-status a:last-child{border:0}.backlog-table-body .pop-status a:hover,.backlog-table-header .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-status:after,.backlog-table-header .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-status.fix,.backlog-table-header .pop-status.fix{bottom:0;top:auto}.backlog-table-body .pop-role,.backlog-table-header .pop-role{background:#050505;color:#fff;display:none;left:65%;list-style-type:none;margin:0;padding:10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-role a,.backlog-table-header .pop-role a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-role a:last-child,.backlog-table-header .pop-role a:last-child{border:0}.backlog-table-body .pop-role a:hover,.backlog-table-header .pop-role a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-role:after,.backlog-table-header .pop-role:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-role a.active,.backlog-table-header .pop-role a.active{background:#9dce0a;color:#fff}.backlog-table-body .pop-points,.backlog-table-header .pop-points{background:#050505;bottom:10px;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px 3rem 10px 10px;position:absolute;width:150px;z-index:99}.backlog-table-body .pop-points a,.backlog-table-header .pop-points a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-points a:last-child,.backlog-table-header .pop-points a:last-child{border:0}.backlog-table-body .pop-points a:hover,.backlog-table-header .pop-points a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-points:after,.backlog-table-header .pop-points:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-points-open,.backlog-table-header .pop-points-open{background:#050505;color:#fff;display:none;left:260px;list-style-type:none;margin:0;padding:10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-points-open a,.backlog-table-header .pop-points-open a{border-bottom:1px solid #444;color:#fff;padding:10px 2px}.backlog-table-body .pop-points-open a:last-child,.backlog-table-header .pop-points-open a:last-child{border:0}.backlog-table-body .pop-points-open a:hover,.backlog-table-header .pop-points-open a:hover{-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-points-open:after,.backlog-table-header .pop-points-open:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-points-open li,.backlog-table-header .pop-points-open li{display:inline-block;width:23%}.backlog-table-body .pop-points-open a,.backlog-table-header .pop-points-open a{display:block;text-align:center}.backlog-table-body .pop-points-open a.active,.backlog-table-body .pop-points-open a:hover,.backlog-table-header .pop-points-open a.active,.backlog-table-header .pop-points-open a:hover{background:#9dce0a;color:#fff}.backlog-table-header .backlog-table-title{border-bottom:2px solid #b8b8b8;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding-right:30px}.backlog-table-header .points{cursor:pointer}.backlog-table-header .header-points span{color:#b8b8b8}.backlog-table-body .row{border-bottom:1px solid #ebebeb;cursor:move;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;position:relative}.backlog-table-body .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .row:hover .icon-drag-v,.backlog-table-body .row:hover .us-settings{opacity:1;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.backlog-table-body .row:last-child{border-bottom:0}.backlog-table-body .row.sortable-placeholder{background:#f5f5f5;height:40px}.backlog-table-body .row.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .row .points .not-clickable:hover{color:#000;cursor:text}.backlog-table-body .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .user-story-name{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.backlog-table-body .user-story-name input{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-right:1rem;vertical-align:super}.backlog-table-body .user-story-name input:checked+a{color:#9dce0a;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.backlog-table-body .user-story-name a{display:inline-block;-webkit-box-flex:20;-webkit-flex-grow:20;-ms-flex-positive:20;flex-grow:20;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.backlog-table-body .tags-block{display:none;margin-bottom:.3rem}.backlog-table-body .tags-block .tag{margin-right:.5rem;padding:.2rem .5rem}.backlog-table-body .blocked{background:#ff8282;border-bottom:1px solid #fff;color:#fff}.backlog-table-body .blocked:hover{background:red;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .blocked a{color:#fff!important}.backlog-table-body .blocked .icon,.backlog-table-body .blocked .icon:hover,.backlog-table-body .blocked a:hover{color:#fff}.backlog-table-body .doom-line{background:red;margin:.2rem 0;padding:.6rem 0;position:relative;width:100%}.backlog-table-body .doom-line span{color:#fff;position:absolute;right:.5rem;top:-3px}.backlog-table-body .icon-drag-v,.backlog-table-body .us-settings a{color:#b8b8b8;-webkit-transition:all .2s ease-in;transition:all .2s ease-in;width:30px}.backlog-table-body .icon-drag-v:hover,.backlog-table-body .us-settings a:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.backlog-table-body .us-settings{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 0 0 2rem;opacity:0}.backlog-table-body .icon-drag-v{cursor:move;opacity:0;padding:.1rem .5rem 0 0}.taskboard-userstory-box .points-value{font-size:.8rem}.taskboard-table-header .task-colum-name .icon{font-size:1rem}.taskboard-table-header .task-colum-name,.taskboard-userstory-box .us-title{font-size:1.2rem}.taskboard-userstory-box .us-title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.taskboard-table-body .column-fold .taskboard-task,.taskboard-table-body .row-fold .taskboard-task{background:0 0;border:0;margin:0;min-height:0}.taskboard-table-body .column-fold .taskboard-task .taskboard-task-inner,.taskboard-table-body .row-fold .taskboard-task .taskboard-task-inner{padding:.2rem}.taskboard-table-body .column-fold .taskboard-task .taskboard-tagline,.taskboard-table-body .column-fold .taskboard-task .taskboard-text,.taskboard-table-body .row-fold .taskboard-task .taskboard-tagline,.taskboard-table-body .row-fold .taskboard-task .taskboard-text{display:none}.taskboard-table-body .column-fold .taskboard-task .avatar,.taskboard-table-body .row-fold .taskboard-task .avatar{height:35px;width:35px}.taskboard-table-body .column-fold .taskboard-task .icon,.taskboard-table-body .row-fold .taskboard-task .icon{display:none}.taskboard-table-body .column-fold .taskboard-task.ui-sortable-helper,.taskboard-table-body .row-fold .taskboard-task.ui-sortable-helper{box-shadow:none}.taskboard-table-body .column-fold .task-column,.taskboard-table-body .row-fold .task-column,.taskboard-table-body .task-column.column-fold,.taskboard-table-body .task-column.row-fold{-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.taskboard-table-body .column-fold .avatar-task-link,.taskboard-table-body .row-fold .avatar-task-link{display:block}.taskboard-table-body .column-fold .avatar-assigned-to,.taskboard-table-body .row-fold .avatar-assigned-to{display:none}.taskboard-table{overflow:hidden;width:100%}.taskboard-table-header{margin-bottom:.5rem;position:relative;width:100%}.taskboard-table-header .taskboard-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;position:absolute}.taskboard-table-header .task-colum-name{background:#f5f5f5;border-top:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin:0 10px 0 0;max-width:300px;padding:.5rem 1rem;position:relative;text-transform:uppercase;width:300px}.taskboard-table-header .task-colum-name:last-child{margin-right:0}.taskboard-table-header .task-colum-name .icon{color:#b8b8b8;margin-right:.3rem;-webkit-transition:color .2s linear;transition:color .2s linear}.taskboard-table-header .task-colum-name .icon:hover{color:#72a114}.taskboard-table-header .task-colum-name .icon.hfold,.taskboard-table-header .task-colum-name .icon.hunfold{display:inline-block;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.taskboard-table-header .task-colum-name.column-fold{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.3rem 0}.taskboard-table-header .task-colum-name.column-fold span{display:none}.taskboard-table-header .task-colum-name.column-fold .hfold,.taskboard-table-header .task-colum-name.column-fold .hunfold{margin:0}.taskboard-table-body{height:700px;overflow-x:scroll;overflow-y:scroll;width:100%}.taskboard-table-body .task-column{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 10px 0 0;max-width:300px;width:300px}.taskboard-table-body .task-column:last-child{margin-right:0}.taskboard-table-body .column-fold .taskboard-task{max-width:40px;width:40px}.taskboard-table-body .task-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:.5rem;min-height:10rem;width:100%}.taskboard-table-body .task-row:hover .new-task{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.taskboard-table-body .task-row.blocked .taskboard-userstory-box{background:rgba(255,0,0,.6);border-radius:3px}.taskboard-table-body .task-row.blocked .points-value,.taskboard-table-body .task-row.blocked a{color:rgba(255,255,255,.9);-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-table-body .task-row.blocked .points-value:hover,.taskboard-table-body .task-row.blocked a:hover{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-table-body .task-row.blocked .taskboard-tasks-box{background:rgba(255,0,0,.1)}.taskboard-table-body .task-row.row-fold{min-height:0}.taskboard-table-body .task-row.row-fold .us-title{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.taskboard-table-body .task-row.row-fold .icon-bulk,.taskboard-table-body .task-row.row-fold .icon-plus,.taskboard-table-body .task-row.row-fold .points-value{display:none}.taskboard-table-body .taskboard-tasks-box{background:#f5f5f5}.taskboard-table-body .taskboard-userstory-box{padding:.5rem .5rem .5rem 1.5rem}.taskboard-table-body .taskboard-userstory-box .icon{color:#b8b8b8;position:absolute;right:.5rem;top:.7rem;-webkit-transition:color .2s linear;transition:color .2s linear}.taskboard-table-body .taskboard-userstory-box .icon:hover{color:#72a114}.taskboard-table-body .taskboard-userstory-box .icon.icon-plus{right:2rem}.taskboard-table-body .taskboard-userstory-box .icon.icon-vfold,.taskboard-table-body .taskboard-userstory-box .icon.icon-vunfold{left:0;right:inherit}.taskboard-table-body .avatar-task-link{display:none}.taskboard-table-body .avatar-assigned-to{display:block}.taskboard-userstory-box{position:relative}.taskboard-userstory-box .tag-list{display:none;margin-bottom:1rem}.taskboard-userstory-box .us-title{margin-bottom:0;margin-right:3rem}.taskboard-userstory-box .points-value{color:#b8b8b8}.taskboard-userstory-box .points-value span{margin-right:.1rem}.points-list a{color:#72a114;margin-left:.5rem}.points-list a:hover span{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.points-list span{opacity:0;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.login-form-container .forgot-pass{font-size:.8rem}.login-form-container .login-password{position:relative}.login-form-container input:focus+.forgot-pass{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.login-form-container .forgot-pass{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.login-form-container .forgot-pass:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.login-form-container .remember-me{vertical-align:top}.login-form-container .remember-me+label{cursor:pointer}.register-form-container .register-text{font-size:.8rem}.register-form-container{display:block}.register-form-container .register-text-top{display:block;margin-bottom:1rem;text-align:center}.forgot-form-container{text-align:center}.change-password-form-container .get-token{font-size:.8rem}.change-password-text{color:#444;text-align:center}.change-password-form-container .token-change-password{position:relative}.change-password-form-container input:focus+.get-token{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.change-password-form-container .get-token{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.change-password-form-container .get-token:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.wiki-nav li{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;border-bottom:1px solid #cdcdcd;text-transform:uppercase}.wiki-nav li:hover .icon{opacity:1;-webkit-transition:opacity 1s linear;transition:opacity 1s linear}.wiki-nav li a{display:block;padding:1rem 0 1rem 1rem}.wiki-nav li a span{cursor:pointer}.wiki-nav li .icon{color:#050505;float:right;opacity:0;-webkit-transition:opacity 1s linear;transition:opacity 1s linear}.wiki-nav li input{background:#444;color:#f5f5f5}.wiki-nav li input::-webkit-input-placeholder{color:#b8b8b8}.wiki-nav li input::-moz-placeholder{color:#b8b8b8}.wiki-nav li input:-moz-placeholder{color:#b8b8b8}.wiki-nav li input:-ms-input-placeholder{color:#b8b8b8}.wiki-nav li.loading{background:#444;border:1px solid #b8b8b8;margin:0;padding:8px;text-align:center;width:100%}.wiki-nav li.loading .icon-spinner{color:#f5f5f5;float:none}.wiki-nav li.loading span{-webkit-animation:loading .5s linear,spin 1s linear infinite;animation:loading .5s linear,spin 1s linear infinite}.wiki-nav .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center}.wiki-summary .username-edition .username{font-size:1.2rem}.wiki-summary:after{clear:both;content:'';display:table}.wiki-summary figure{float:left;margin-right:.5rem;vertical-align:sub;width:32px}.wiki-summary ul{-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.wiki-summary .username-edition{min-width:240px}.wiki-summary .username-edition span{display:block;float:none}.wiki-summary .username-edition .username{color:#9dce0a;white-space:nowrap}.wiki-summary .button{color:#fff;float:right}.admin-menu li{font-size:1.6rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;border-bottom:1px solid #b8b8b8;text-transform:uppercase}.admin-menu li:last-child{border-bottom:0}.admin-menu a{display:block;padding:1rem 0 1rem 1rem}.admin-menu a.active .icon,.admin-menu a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-menu .icon{color:#050505;float:right;opacity:0}.admin-common .total{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-common header h1{margin-bottom:0}.admin-common .admin-subtitle{color:#b8b8b8;margin:0}.admin-common .total{background-color:#f5f5f5;color:#444;padding:1rem}.admin-common .total:hover .edit-value{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu li{font-size:1.6rem}.admin-submenu h1{font-size:2rem}.admin-submenu li{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-submenu h1{color:#fff}.admin-submenu li{border-bottom:1px solid #a6b2a7;text-transform:uppercase}.admin-submenu li:last-child{border-bottom:0}.admin-submenu a{color:#fff;display:block;padding:1rem 0 1rem 1rem}.admin-submenu a.active,.admin-submenu a:hover{color:#050505}.admin-submenu a.active .icon,.admin-submenu a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu .icon{color:#fff;float:right;opacity:0}.admin-submenu .button-gray{padding:.5rem 0;text-align:center}.admin-submenu .button-gray:hover{background-color:#617463}.admin-submenu-roles li{font-size:1.6rem}.admin-submenu-roles h1{font-size:2rem}.admin-submenu-roles li{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-submenu-roles h1{color:#fff}.admin-submenu-roles li{border-bottom:1px solid #a6b2a7;text-transform:uppercase}.admin-submenu-roles li:last-child{border-bottom:0}.admin-submenu-roles a{color:#fff;display:block;padding:1rem 0 1rem 1rem}.admin-submenu-roles a.active,.admin-submenu-roles a:hover{color:#050505}.admin-submenu-roles a.active .icon,.admin-submenu-roles a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu-roles .icon{color:#fff;float:right;opacity:0}.admin-submenu-roles .button-gray{padding:.5rem 0;text-align:center}.admin-submenu-roles .button-gray:hover{background-color:#617463}.admin-roles .check input~.check-text{font-size:.8rem}.admin-roles .edit-value{font-size:1rem}.admin-roles .role-name{font-size:2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;color:#444}.admin-roles .edit-value{color:#b8b8b8;cursor:pointer;margin-left:.5rem;opacity:0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-roles .edit-role{-webkit-box-align:left;-webkit-align-items:left;-ms-flex-align:left;align-items:left;background-color:#f5f5f5;display:none;margin-bottom:1rem;padding:.5rem}.admin-roles .edit-role input{background-color:#fff;width:50%}.admin-roles .edit-role .icon-floppy{color:#b8b8b8;margin-left:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.admin-roles .edit-role .icon-floppy:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.admin-roles .any-computable-role{background:red;color:#fff;margin-bottom:.5rem;padding:.5rem}.admin-roles .general-category{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;padding-bottom:2rem}.admin-roles .general-category .check{margin-left:.5rem}.admin-roles .check{background-color:#dcdcdc;border-radius:2px;cursor:pointer;height:1.5rem;overflow:hidden;position:relative;width:65px}.admin-roles .check input{cursor:pointer;height:500px;left:-10px;opacity:0;position:absolute;top:-10px;width:500px;z-index:999}.admin-roles .check input+div{background-color:#585858;height:25px;-webkit-transition:all .2s linear;transition:all .2s linear;width:50%}.admin-roles .check input~.check-text{color:#fff;position:absolute;top:.1rem}.admin-roles .check input~.check-yes{opacity:0;right:.5rem}.admin-roles .check input~.check-no{left:.5rem;opacity:.6}.admin-roles .check input:checked+div{background-color:#74a218;margin-left:50%;-webkit-transition:all .2s linear;transition:all .2s linear}.admin-roles .check input:checked~.check-yes{opacity:.6;right:.4rem}.admin-roles .check input:checked~.check-no{left:.4rem;opacity:0}.admin-functionalities .functionality .icon{font-size:3rem}.admin-functionalities .functionality span{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-functionalities form{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.admin-functionalities .functionality{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-color:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin-bottom:.3rem;margin-right:.3rem;opacity:.5;padding:1rem;position:relative;-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:top;width:32%}.admin-functionalities .functionality.active{background-color:#e9f0da;opacity:1}.admin-functionalities .functionality .icon{-webkit-flex-basis:60px;-ms-flex-preferred-size:60px;flex-basis:60px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin:0 auto;min-height:60px}.admin-functionalities .functionality .desc{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.admin-functionalities .functionality .activate-input{display:none}.admin-functionalities .functionality .activate-input+label{color:#fff;cursor:pointer;display:block;text-align:center}.admin-functionalities .functionality span{display:block}.admin-functionalities .functionality select{margin-top:1rem}.admin-functionalities .videoconference-attributes select{margin-bottom:.5rem}.admin-functionalities .button-green{color:#fff;display:block;text-align:center}.admin-membership-table .check input~.check-text,.admin-membership-table .row-admin label{font-size:.8rem}.admin-membership-table .delete{font-size:1.2rem}.admin-membership-table .avatar .name,.admin-membership-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-membership-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.admin-membership-table .avatar figcaption{margin-left:1rem;width:75%}.admin-membership-table .avatar figcaption span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.admin-membership-table .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:35px}.admin-membership-table .avatar .email,.admin-membership-table .avatar .name{display:block;width:100%}.admin-membership-table .avatar .email{color:#b8b8b8}.admin-membership-table .header-role,.admin-membership-table .header-status{padding-left:.5rem}.admin-membership-table .row-role{padding-right:1rem}.admin-membership-table .row-status{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.admin-membership-table .active,.admin-membership-table .pending{padding:8px}.admin-membership-table .active{background-color:#f5f5f5}.admin-membership-table .pending{background-color:#ff8282;color:#fff}.admin-membership-table .pending .icon{float:rsdsdfdvsdvight}.admin-membership-table .pending:hover{background-color:red;color:#fff;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.admin-membership-table .delete{color:#b8b8b8}.admin-membership-table .delete:hover{color:red}.admin-membership-table .row-admin input{vertical-align:middle}.admin-membership-table .header-member,.admin-membership-table .header-role,.admin-membership-table .row-member,.admin-membership-table .row-role{-webkit-flex-basis:210px;-ms-flex-preferred-size:210px;flex-basis:210px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;min-width:210px}.admin-membership-table .header-admin,.admin-membership-table .row-admin{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;min-width:70px}.admin-membership-table .header-status,.admin-membership-table .row-status{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.admin-membership-table .check{background-color:#dcdcdc;border-radius:2px;cursor:pointer;height:1.5rem;overflow:hidden;position:relative;width:65px}.admin-membership-table .check input{cursor:pointer;height:500px;left:-10px;opacity:0;position:absolute;top:-10px;width:500px;z-index:999}.admin-membership-table .check input+div{background-color:#585858;height:25px;-webkit-transition:all .2s linear;transition:all .2s linear;width:50%}.admin-membership-table .check input~.check-text{color:#fff;position:absolute;top:.1rem}.admin-membership-table .check input~.check-yes{opacity:0;right:.5rem}.admin-membership-table .check input~.check-no{left:.5rem;opacity:.6}.admin-membership-table .check input:checked+div{background-color:#74a218;margin-left:50%;-webkit-transition:all .2s linear;transition:all .2s linear}.admin-membership-table .check input:checked~.check-yes{opacity:.6;right:.4rem}.admin-membership-table .check input:checked~.check-no{left:.4rem;opacity:0}.project-details .delete-project{font-size:.8rem}.project-details .privacy-settings label,.project-details input,.project-details label,.project-details textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.project-details form{max-width:700px;width:100%}.project-details fieldset{margin-bottom:1rem}.project-details label{display:block;margin-bottom:.2rem}.project-details textarea{height:10rem}.project-details .privacy-settings{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:2rem}.project-details .privacy-settings div{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-details .privacy-settings div:first-child{margin-right:.5rem}.project-details .privacy-settings label{background:#fff;border:1px solid #f5f5f5;cursor:pointer;display:block;text-align:center}.project-details .privacy-settings input:checked+label{background:#9dce0a;color:#fff}.project-details .button-green{color:#fff;display:block;text-align:center}.project-details .delete-project{display:block;margin-top:1rem}.default-values fieldset{margin-bottom:1rem}.default-values fieldset:last-child{margin-top:1.5rem}.default-values label,.default-values select{display:inline-block;width:49.7%}.default-values a{color:#fff;display:block;text-align:center}.project-values-row .icon,.project-values-settings a{font-size:1.2rem}.project-values-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.project-values-row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1rem}.project-values-row div{margin-left:1rem;position:relative}.project-values-row .icon{color:#b8b8b8;opacity:0}.project-values-row .icon:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.project-values-header{border-bottom:2px solid #b8b8b8}.project-values-body .project-values-row:hover{background:#f6fceb;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.project-values-body .project-values-row:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.project-values-name{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.project-values-value{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-values-value .checksley-error-list{left:0;right:auto;top:35px;white-space:nowrap}.project-values-isclosed,.project-values-settings{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:right}.project-values-settings a{color:#555;margin-right:.5rem}.project-values-settings a:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.project-values-settings a:hover .icon-delete{color:red}.admin-third-parties .help .alt-image,.admin-third-parties .help code,.admin-third-parties .select-input-text .help-copy{font-size:.8rem}.admin-third-parties input,.admin-third-parties label,.admin-third-parties textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-third-parties form{margin:1rem 0;max-width:700px;width:100%}.admin-third-parties fieldset{margin-bottom:1rem}.admin-third-parties label{display:block;margin-bottom:.2rem}.admin-third-parties textarea{height:10rem}.admin-third-parties .button-green{color:#fff;display:block;text-align:center}.admin-third-parties .select-input-text .field-with-option{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.admin-third-parties .select-input-text .option-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border:1px solid #b8b8b8;border-left:0;border-radius:0 5px 5px 0;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0 1rem}.admin-third-parties .select-input-text .help-copy{opacity:0}.admin-third-parties .select-input-text .help-copy.visible{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.admin-third-parties .help{margin-top:2rem}.admin-third-parties .help h3{font-family:opensans-semibold;margin-bottom:1rem}.admin-third-parties .help ol{padding:0 0 0 2rem}.admin-third-parties .help ol span{font-family:opensans-semibold}.admin-third-parties .help .img{margin-bottom:1rem}.admin-third-parties .help .alt-image{font-style:italic}.admin-third-parties .help code{background:#f5f5f5;direction:ltr;display:block;font-family:'courier new',monospace;line-height:1.4rem;margin-bottom:1rem;padding:.5rem;unicode-bidi:embed;white-space:pre;width:100%}.admin-third-parties .help .code-info{padding-left:1rem}.admin-third-parties .help .code-info li{margin-bottom:.5rem}.admin-third-parties .help .code-info span{font-family:opensans-semibold}.admin-contrib .help .alt-image,.admin-contrib .help code,.admin-contrib .select-input-text .help-copy{font-size:.8rem}.admin-contrib input[type=text],.admin-contrib label,.admin-contrib textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-contrib form{margin:1rem 0;max-width:700px;width:100%}.admin-contrib fieldset{margin-bottom:1rem}.admin-contrib label{display:block;margin-bottom:.2rem}.admin-contrib textarea{height:10rem}.admin-contrib .button-green{color:#fff;display:block;text-align:center}.admin-contrib .select-input-text .field-with-option{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.admin-contrib .select-input-text .option-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border:1px solid #b8b8b8;border-left:0;border-radius:0 5px 5px 0;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0 1rem}.admin-contrib .select-input-text .help-copy{opacity:0}.admin-contrib .select-input-text .help-copy.visible{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.admin-contrib .help{margin-top:2rem}.admin-contrib .help h3{font-family:opensans-semibold;margin-bottom:1rem}.admin-contrib .help ol{padding:0 0 0 2rem}.admin-contrib .help ol span{font-family:opensans-semibold}.admin-contrib .help .img{margin-bottom:1rem}.admin-contrib .help .alt-image{font-style:italic}.admin-contrib .help code{background:#f5f5f5;direction:ltr;display:block;font-family:'courier new',monospace;line-height:1.4rem;margin-bottom:1rem;padding:.5rem;unicode-bidi:embed;white-space:pre;width:100%}.admin-contrib .help .code-info{padding-left:1rem}.admin-contrib .help .code-info li{margin-bottom:.5rem}.admin-contrib .help .code-info span{font-family:opensans-semibold}.user-profile form .avatar-container p{font-size:.5rem}.user-profile .delete-account,.user-profile form .avatar-container .use-gravatar{font-size:.8rem}.user-profile form .avatar-container .icon-spinner{font-size:2rem}.user-profile label{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user-profile form .avatar-container span{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.user-profile form{max-width:700px;width:100%}.user-profile form .container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.user-profile form .avatar-container{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:1rem}.user-profile form .avatar-container .image-container{position:relative}.user-profile form .avatar-container img{border:2px solid #fff;border-radius:8%;width:100%}.user-profile form .avatar-container .overlay{background:rgba(255,255,255,.9);bottom:0;display:none;left:0;position:absolute;right:0;top:0}.user-profile form .avatar-container .icon-spinner{-webkit-animation:spin infinite .8s linear;animation:spin infinite .8s linear;color:#b8b8b8;left:40%;position:absolute;top:40%}.user-profile form .avatar-container p{line-height:.8rem;margin-bottom:.3rem;text-align:center}.user-profile form .avatar-container .use-gravatar{cursor:pointer;display:inline-block;text-align:center;width:100%}.user-profile form .data{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.user-profile fieldset{margin-bottom:1rem}.user-profile .submit{margin-top:2rem}.user-profile label{display:block;margin-bottom:.5rem}.user-profile .button-green{color:#fff;cursor:pointer;display:block;padding:12px;text-align:center}.user-profile .delete-account{display:block;margin-top:1rem}.user-change-password label{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user-change-password fieldset{margin-bottom:1rem;width:50%}.user-change-password fieldset:last-child{margin-top:2rem}.user-change-password label{display:block;margin-bottom:.5rem}.user-change-password .button-green{color:#fff;display:block;padding:12px;text-align:center}.policy-table .policy-table-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.policy-table .policy-table-row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.policy-table .policy-table-header{border-bottom:2px solid #b8b8b8}.policy-table .policy-table-all,.policy-table .policy-table-involved,.policy-table .policy-table-none,.policy-table .policy-table-project{padding:1rem}.policy-table .policy-table-project{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.policy-table .policy-table-all,.policy-table .policy-table-involved,.policy-table .policy-table-none{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.policy-table input{display:none}.policy-table input:checked+label{background:#72a114;-webkit-transition:background .3s linear;transition:background .3s linear}.policy-table label{background:#b8b8b8;border-radius:5px;color:#fff;display:block;padding:.5rem}.policy-table label:hover{background:#9dce0a;cursor:pointer;-webkit-transition:background .3s linear;transition:background .3s linear}.team-filters nav li{font-size:1.6rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.team-filters .search-in{margin-bottom:1rem;position:relative}.team-filters nav li{border-bottom:1px solid #b8b8b8;text-transform:uppercase}.team-filters nav li:last-child{border-bottom:0}.team-filters nav a{display:block;padding:1rem 0 1rem 1rem}.team-filters nav a.active,.team-filters nav a:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.team-filters nav .active,.team-filters nav a.active.icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.team-filters nav .icon{color:#050505;float:right;opacity:0}.table-team .leave-project,.table-team .popover,.table-team .popover a{font-size:.8rem}.table-team .attribute .icon,.table-team .attribute .points{font-size:2rem}.table-team .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.table-team .attribute .points,.table-team .avatar .name,.table-team .team-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.table-team .row{padding:.5rem}.table-team .username{-webkit-box-flex:3;-webkit-flex:3;-ms-flex:3;flex:3;min-width:300px}.table-team .member-stats{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:6;-webkit-flex:6;-ms-flex:6;flex:6;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.table-team .attribute{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;position:relative;text-align:center}.table-team .attribute .icon,.table-team .attribute .points{color:#444}.table-team .attribute .icon.top,.table-team .attribute .points.top{color:#9dce0a}.table-team .attribute .top{color:#9dce0a;opacity:1}.table-team .attribute:hover .popover{display:block}.table-team .leave-project{color:#b8b8b8;display:block}.table-team .leave-project .icon{margin-right:.2rem}.table-team .leave-project:hover .icon{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.table-team .team-header{border-bottom:0}.table-team .hero{width:100%}.table-team .hero .row{background:#fcfcfc;border-bottom:0;margin:1rem 0}.table-team .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.table-team .avatar img{-webkit-flex-basis:66px;-ms-flex-preferred-size:66px;flex-basis:66px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:66px}.table-team .avatar figcaption{margin-left:1rem;width:65%}.table-team .avatar figcaption span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.table-team .avatar .name,.table-team .avatar .position{display:block;width:100%}.table-team .avatar .position{color:#b8b8b8}.table-team .popover{background:#050505;bottom:30px;color:#fff;display:none;left:0;list-style-type:none;margin:0;padding:10px;position:absolute;width:100%;z-index:99}.table-team .popover a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.table-team .popover a:last-child{border:0}.table-team .popover a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.table-team .popover:after{background:#050505;bottom:-5px;content:'';height:15px;left:50%;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.lightbox-generic-notion section{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px}.kanban-table-header,.taskboard-table-header{height:40px} \ No newline at end of file + */.pika-single{display:block;position:relative;width:240px;padding:8px;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-disabled .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff!important;background:#ff8000!important;box-shadow:none!important;border-radius:3px!important}.hll{background-color:#ffc}.c{color:#998;font-style:italic}.err{background-color:#e3d2d2;color:#a61717}.k,.o{color:#000;font-weight:700}.cm{color:#998;font-style:italic}.cp{color:#999;font-style:italic;font-weight:700}.c1{color:#998;font-style:italic}.cs{color:#999;font-style:italic;font-weight:700}.gd{background-color:#fdd;color:#000}.ge{color:#000;font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{background-color:#dfd;color:#000}.go{color:#888}.gp{color:#555}.gs{font-weight:700}.gu{color:#aaa}.gt{color:#a00}.kc,.kd,.kn,.kp,.kr{color:#000;font-weight:700}.kt{color:#458;font-weight:700}.m{color:#099}.s{color:#d01040}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:700}.no{color:teal}.nd{color:#3c5d5d;font-weight:700}.ni{color:purple}.ne,.nf,.nl{color:#900;font-weight:700}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{color:#000;font-weight:700}.w{color:#bbb}.mf,.mh,.mi,.mo{color:#099}.s2,.sb,.sc,.sd,.se,.sh,.si,.sx{color:#d01040}.sr{color:#009926}.s1{color:#d01040}.ss{color:#990073}.bp{color:#999}.vc,.vg,.vi{color:teal}.il{color:#099}*{box-sizing:border-box}a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{border:0;font:inherit;font-size:100%;margin:0;padding:0;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}blockquote,q{quotes:none}blockquote:after,blockquote:before,q:after,q:before{content:''}table{border-collapse:collapse;border-spacing:0}body{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.icon{font-family:taiga}html{min-height:100%;width:100%}body{background:#fff;color:#444;min-height:100%;width:100%}body .master.ng-animate{-webkit-transition:0;transition:0}body .menu,body.open-projects-nav .projects-nav{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .master{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .master.ng-animate{-webkit-transition:0;transition:0}body.open-projects-nav .menu{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav .projects-nav-overlay{opacity:.9;-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0);-webkit-transition:all 1s ease;transition:all 1s ease}body.open-projects-nav.closed-projects-nav .projects-nav{-webkit-transform:translate3d(-300px,0,0);transform:translate3d(-300px,0,0);-webkit-transition:-webkit-transform 1s ease;transition:transform 1s ease}body.open-projects-nav.closed-projects-nav .projects-nav-overlay{opacity:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition:all 1s ease;transition:all 1s ease}body.open-projects-nav.closed-projects-nav .master,body.open-projects-nav.closed-projects-nav .menu{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}body.loading-project{overflow:hidden}body.loading-project .projects-nav-overlay{opacity:1;overflow:hidden;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}body.loading-project .projects-nav-overlay div{opacity:1;-webkit-transition:opacity 1s ease;transition:opacity 1s ease}.loader-active{overflow:hidden}.master{background:#fff;height:100%;min-height:100%;position:relative}.wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-height:100vh;padding-left:90px}.menu-secondary{background:#f5f5f5;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;min-height:100vh;min-width:0;padding:2rem 1rem;width:320px}.menu-secondary.filters-bar{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;padding:0;-webkit-transition:all .2s linear;transition:all .2s linear;width:0}.menu-secondary.filters-bar.active{padding:2em 1em;-webkit-transition:all .2s linear;transition:all .2s linear;width:260px}.menu-secondary.filters-bar.active .filters-inner{opacity:1;-webkit-transition:all .4s ease-in;transition:all .4s ease-in}.menu-tertiary{background-color:#8b9e8d;-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;min-height:100vh;padding:2em 1em;width:255px}.extrabar{background:#f5f5f5}.main{-webkit-box-flex:4;-webkit-flex:4;-ms-flex:4;flex:4;min-width:600px;padding:2rem 2rem 1rem}.hidden{display:none!important}.header-with-actions{-webkit-align-content:stretch;-ms-flex-line-pack:stretch;align-content:stretch;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:1rem}.header-with-actions .action-buttons{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.header-with-actions .button{color:#fff;float:right;margin-left:10px}.header-with-actions .button:hover{color:#fff}.header-with-actions h1{margin-bottom:0}@-webkit-keyframes loading{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0}100%{-webkit-filter:blur(0);filter:blur(0);opacity:1}}@keyframes loading{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0}100%{-webkit-filter:blur(0);filter:blur(0);opacity:1}}@-webkit-keyframes rotate{50%{-webkit-filter:invert(1);filter:invert(1);-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{50%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes formSlide{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0;-webkit-transform:translateY(10rem);transform:translateY(10rem)}50%{-webkit-filter:blur(0);filter:blur(0)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes formSlide{0%{-webkit-filter:blur(5px);filter:blur(5px);opacity:0;-webkit-transform:translateY(10rem);transform:translateY(10rem)}50%{-webkit-filter:blur(0);filter:blur(0)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes loadBar{0%{-webkit-box-flex:1;-webkit-flex:1;flex:1}10%{-webkit-box-flex:10;-webkit-flex:10;flex:10}20%{-webkit-box-flex:1;-webkit-flex:1;flex:1}}@keyframes loadBar{0%{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}10%{-webkit-box-flex:10;-webkit-flex:10;-ms-flex:10;flex:10}20%{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}}h2{font-size:2rem}h1,h1 span{font-size:3rem}h1,h2{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}@font-face{font-family:OpenSans-CondLight;src:url(../fonts/OpenSans-CondLight.eot?#iefix) format("embedded-opentype"),url(../fonts/OpenSans-CondLight.woff) format("woff"),url(../fonts/OpenSans-CondLight.ttf) format("truetype"),url(../fonts/OpenSans-CondLight.svgOpenSans-CondLight) format("svg")}@font-face{font-family:opensans-regular;src:url(../fonts/opensans-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/opensans-regular.woff) format("woff"),url(../fonts/opensans-regular.ttf) format("truetype"),url(../fonts/opensans-regular.svgopensans-regular) format("svg")}@font-face{font-family:opensans-semibold;src:url(../fonts/opensans-semibold.eot?#iefix) format("embedded-opentype"),url(../fonts/opensans-semibold.woff) format("woff"),url(../fonts/opensans-semibold.ttf) format("truetype"),url(../fonts/opensans-semibold.svgopensans-semibold) format("svg")}@font-face{font-family:taiga;src:url(../fonts/taiga.eot?#iefix) format("embedded-opentype"),url(../fonts/taiga.woff) format("woff"),url(../fonts/taiga.ttf) format("truetype"),url(../fonts/taiga.svgtaiga) format("svg")}h1,h2,h3,h4,h5,h6{color:#050505;font-weight:400}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}h1{line-height:3.4rem;margin-bottom:1rem;text-transform:uppercase}h1 span{line-height:3.4rem;margin-right:.5rem;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap}h1 span.green,h1 span:last-child{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}h1 .project-name{display:inline-block;max-width:60%}h1 .project-name-short{display:inline-block;max-width:40%}h1 .green{color:#72a114}h1 .date{max-width:500px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#b8b8b8}h2{margin-bottom:1rem}p{margin:0 0 20px}p img{margin:0}em{font-style:italic}strong{font-weight:700}hr{border:solid #ddd;border-width:1px 0 0;clear:both;height:0;margin:10px 0 30px}a,a:visited{color:#444;text-decoration:none}a:hover,a:visited:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}[data-icon]:before{content:attr(data-icon);font-family:taiga!important;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal!important;font-variant:normal!important;font-weight:400!important;line-height:1;speak:none;text-transform:none!important}[class*=' icon-']:before,[class^=icon-]:before{font-family:taiga!important;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-style:normal!important;font-variant:normal!important;font-weight:400!important;line-height:1;speak:none;text-transform:none!important}.icon-bug:before{content:'a'}.icon-copy:before{content:'b'}.icon-minimize:before{content:'c'}.icon-maximize:before{content:'d'}.icon-comment:before{content:'e'}.icon-plus:before{content:'f'}.icon-attachments:before{content:'g'}.icon-edit:before{content:'h'}.icon-documents:before{content:'i'}.icon-delete:before{content:'j'}.icon-arrow-bottom:before{content:'k'}.icon-arrow-left:before{content:'l'}.icon-arrow-right:before{content:'m'}.icon-arrow-up:before{content:'n'}.icon-briefcase:before{content:'o'}.icon-caret-down:before{content:'p'}.icon-caret-up:before{content:'q'}.icon-check-square:before{content:'r'}.icon-notification-error:before{content:'s'}.icon-settings:before{content:'t'}.icon-document:before{content:'u'}.icon-warning:before{content:'v'}.icon-move:before{content:'w'}.icon-drag-h:before{content:'x'}.icon-drag-v:before{content:'y'}.icon-filter:before{content:'z'}.icon-github:before{content:'A'}.icon-help:before{content:'B'}.icon-reload:before{content:'C'}.icon-writer:before{content:'D'}.icon-stats:before{content:'E'}.icon-floppy:before{content:'F'}.icon-idea:before{content:'G'}.icon-warning-alt:before{content:'H'}.icon-video:before{content:'I'}.icon-bulk:before{content:'K'}.icon-vunfold:before{content:'M'}.icon-tasks:before{content:'O'}.icon-kanban:before{content:'P'}.icon-search:before{content:'Q'}.icon-wiki:before{content:'L'}.icon-team:before{content:'T'}.icon-spinner:before{content:'J'}.icon-vfold:before{content:'N'}.icon-issues:before{content:'U'}.icon-backlog:before{content:'R'}.icon-iocaine:before{content:'S'}.icon-closed-eye:before{content:'V'}.icon-open-eye:before{content:'W'}.icon-archive:before{content:'X'}.icon-capslock:before{content:'Y'}.icon-upload:before{content:'Z'}.login-main .tagline{font-size:2rem}.login-main .logo{font-size:3rem}.login-main .logo,.login-main .tagline{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.login-main{background:url(/images/bg.png) center center no-repeat;background-size:cover;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.login-main fieldset{margin-bottom:.5rem}.login-main .login-container{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px}.login-main .logo-svg{padding:0 33%;text-align:center;width:100%}.login-main .logo{color:#fff;margin-bottom:1rem;text-align:center}.login-main .tagline{color:#fff;line-height:2rem;margin-bottom:1rem;text-align:center;text-transform:uppercase}.login-main form{margin-bottom:1rem}.login-main input{background:#fff}.login-main input::-webkit-input-placeholder{color:#b8b8b8}.login-main input::-moz-placeholder{color:#b8b8b8}.login-main input:-moz-placeholder{color:#b8b8b8}.login-main input:-ms-input-placeholder{color:#b8b8b8}.login-main .login-text,.login-main .register-text{text-align:center}.login-main .login-text a:hover,.login-main .register-text a:hover{color:#9dce0a}.login-main .button{color:#fff;display:block;text-align:center}.login-main a:hover{color:#fff}.login-main .checksley-error-list{right:1rem}.login-main .checksley-error-list+.forgot-pass{display:none}.invitation-main .invitation-form .forgot-pass,.invitation-main .register-text{font-size:.8rem}.invitation-main .avatar .person-name,.invitation-main .invitation-text{font-size:2rem}.invitation-main .invitation-text .project-name{font-size:3rem}.invitation-main .avatar .person-name,.invitation-main .invitation-text{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.invitation-main{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.invitation-main .invitation-container{-webkit-flex-basis:650px;-ms-flex-preferred-size:650px;flex-basis:650px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:650px}.invitation-main .logo{margin:1rem auto;width:150px}.invitation-main .avatar{margin:0 auto 1rem;text-align:center;width:250px}.invitation-main .avatar .person-name{color:#fff;text-transform:uppercase}.invitation-main .avatar img{display:block;text-align:center;width:50px}.invitation-main .invitation-text{color:#fff;line-height:2rem;text-align:center;text-transform:uppercase}.invitation-main .invitation-text .project-name{display:block}.invitation-main .invitation-form{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.invitation-main .invitation-form fieldset{margin-bottom:.5rem}.invitation-main .invitation-form input{background:#fff;color:#555;position:relative}.invitation-main .invitation-form input::-webkit-input-placeholder{color:#b8b8b8}.invitation-main .invitation-form input::-moz-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:-moz-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:-ms-input-placeholder{color:#b8b8b8}.invitation-main .invitation-form input:focus+.forgot-pass{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.invitation-main .invitation-form .forgot-pass{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.invitation-main .invitation-form .forgot-pass:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.invitation-main .invitation-form .button{color:#fff;display:block;text-align:center}.invitation-main .invitation-form .button:hover{background:#9dce0a}.invitation-main .invitation-form .button-github:hover{background:#000}.invitation-main .login-form,.invitation-main .register-form{-webkit-flex-basis:200px;-ms-flex-preferred-size:200px;flex-basis:200px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:1rem;text-align:center;width:200px}.invitation-main .login-form .form-header,.invitation-main .register-form .form-header{color:#999}.invitation-main .register-form fieldset:last-child{margin-bottom:1rem}.invitation-main .register-text{color:#fff}.invitation-main .register-text a{color:#72a114}.invitation-main .register-text a:hover{color:#9dce0a}.invitation-main .login-form{border-right:1px solid #fff}blockquote cite,sup{font-size:.8rem}.empty span.title{font-size:2rem}.empty .icon{font-size:3rem}.empty span.title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}blockquote,blockquote p{color:#777;font-style:italic;line-height:24px}blockquote{border-left:1px solid #ddd;margin:0 0 20px;padding:9px 20px 0 19px}blockquote cite{color:#555;display:block}blockquote cite:before{content:'\2014 \0020'}ol,ul{margin-bottom:20px}ul{list-style:none}ol{list-style:decimal}sup{vertical-align:super}.icon{vertical-align:middle}.clickable{cursor:pointer}.not-clickable{cursor:default}.draggable{cursor:move}.pika-single{z-index:999999}.pika-single .pika-title{color:#444}.pika-single .is-selected .pika-button{background:#72a114;border-radius:0!important;box-shadow:inset 0 1px 3px #72a114}.pika-single .is-today .pika-button{color:#72a114}.pika-single .is-today.is-selected button{color:#fff}.pika-single .pika-button:hover{background:#9dce0a!important;border-radius:0!important;box-shadow:inset 0 1px 3px #9dce0a!important}.empty{border:1px dashed #b8b8b8;color:#b8b8b8;min-height:10rem;padding:5% 0;text-align:center}.empty .icon{margin-bottom:2rem}.empty span{display:block}.empty span.title{margin-bottom:1rem;text-transform:uppercase}.checksley-error-list{font-size:.8rem}input[type=number],input[type=text],input[type=password],input[type=email],input[type=date],select,textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}fieldset{border:0;margin:0;padding:0;position:relative;width:100%}fieldset label~.checksley-error-list{top:31px}input[type=number],input[type=text],input[type=password],input[type=email],input[type=date],select,textarea{background:#f5f5f5;border:1px solid #b8b8b8;color:#444;margin:0;padding:8px;width:100%}input[type=number]::-webkit-input-placeholder,input[type=text]::-webkit-input-placeholder,input[type=password]::-webkit-input-placeholder,input[type=email]::-webkit-input-placeholder,input[type=date]::-webkit-input-placeholder,select::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#b8b8b8}input[type=number]::-moz-placeholder,input[type=text]::-moz-placeholder,input[type=password]::-moz-placeholder,input[type=email]::-moz-placeholder,input[type=date]::-moz-placeholder,select::-moz-placeholder,textarea::-moz-placeholder{color:#b8b8b8}input[type=number]:-moz-placeholder,input[type=text]:-moz-placeholder,input[type=password]:-moz-placeholder,input[type=email]:-moz-placeholder,input[type=date]:-moz-placeholder,select:-moz-placeholder,textarea:-moz-placeholder{color:#b8b8b8}input[type=number]:-ms-input-placeholder,input[type=text]:-ms-input-placeholder,input[type=password]:-ms-input-placeholder,input[type=email]:-ms-input-placeholder,input[type=date]:-ms-input-placeholder,select:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#b8b8b8}textarea{min-height:10rem;resize:vertical}.checksley-error-list{margin-bottom:0;position:absolute;right:2rem;top:10px}.checksley-error-list li{color:red;padding:.2rem}.error-main{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.error-main .error-container{color:#fff;-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;text-align:center}.error-main .logo-svg{padding:0 32%;text-align:center;width:100%}.error-main h1{color:#fff;margin-bottom:3rem}.error-main a{color:#72a114}.error-main a:hover{color:#9dce0a}.backlog .new-us{float:right}.backlog-menu{background:#f5f5f5;color:#050505;margin-bottom:1rem;padding:.5rem}.backlog-menu:after{clear:both;content:'';display:table}.backlog-menu .trans-button{display:inline-block;margin-right:1rem;padding:.3rem 0}.backlog-menu .trans-button.move-to-current-sprint{display:none}.backlog-menu .trans-button span{vertical-align:middle}.taskboard .graphics-container{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow:overflow-y}.taskboard .graphics-container.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:300px}.duty-data-container,.points-per-role .popover a,.points-per-role .popover.fix a,.us-detail-progress-bar .tasks-completed,.us-status .priority-data .pop-priority a,.us-status .severity-data .pop-severity a,.us-status .status-data .pop-status a,.us-status .type-data .pop-type a,.us-story-main-data .us-title .block-desc-container,.us-story-main-data .us-title .us-related-task{font-size:.8rem}.us-detail-status,.us-story-main-data .us-title,.us-story-main-data .us-title .icon-edit,.us-story-main-data .us-title .icon-floppy{font-size:1.2rem}.blocked-warning .blocked,.blocked-warning .icon,.issue-nav a,.points-per-role .points,.us-story-main-data .us-title .us-name,.us-story-main-data .us-title .us-number{font-size:2rem}.blocked-warning .blocked,.points-per-role .points,.us-story-main-data .us-title .us-number{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.points-per-role .popover,.points-per-role .popover.fix,.us-status .priority-data .pop-priority,.us-status .severity-data .pop-severity,.us-status .status-data .pop-status,.us-status .type-data .pop-type,.us-story-main-data .us-title{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.us-story-main-data .us-title .block-description-title,.us-story-main-data .us-title.blocked .unblock{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.duty-content .save-container .loading-spinner,.duty-data-container .level-name .loading-spinner,.us-detail-settings .loading-spinner,.us-story-main-data .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;max-height:1rem;max-width:1rem;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.us-story-main-data{margin-bottom:2rem}.us-story-main-data .us-title{background:#f5f5f5;margin-bottom:.5rem;padding:1rem;position:relative;-webkit-transition:all .2s linear;transition:all .2s linear}.us-story-main-data .us-title.blocked{background:red;-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:middle}.us-story-main-data .us-title.blocked .us-title-text,.us-story-main-data .us-title.blocked input{margin-bottom:.5rem}.us-story-main-data .us-title.blocked .us-name,.us-story-main-data .us-title.blocked .us-number,.us-story-main-data .us-title.blocked .us-related-task{color:#fff}.us-story-main-data .us-title.blocked a{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title.blocked a:hover{color:#ff8282}.us-story-main-data .us-title.blocked .unblock{color:#fff;float:right}.us-story-main-data .us-title.blocked .unblock:hover{color:#ff8282;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title p{margin-bottom:0}.us-story-main-data .us-title .us-edit-name-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.us-story-main-data .us-title .edit-subject{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.us-story-main-data .us-title input{background:#fff;-webkit-box-flex:9;-webkit-flex-grow:9;-ms-flex-positive:9;flex-grow:9}.us-story-main-data .us-title .save-container{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.us-story-main-data .us-title .us-title-text{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:0;max-width:94%}.us-story-main-data .us-title .us-title-text:hover .icon-edit{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.us-story-main-data .us-title .us-number{color:#b8b8b8;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;line-height:2.2rem;margin-right:.5rem}.us-story-main-data .us-title .us-name{color:#444;display:inline-block;line-height:2.2rem;padding-right:1rem;width:100%}.us-story-main-data .us-title .icon-edit,.us-story-main-data .us-title .icon-floppy{color:#b8b8b8;margin-left:.5rem}.us-story-main-data .us-title .icon-edit{opacity:0}.us-story-main-data .us-title .us-related-task{color:#b8b8b8;margin-top:.5rem}.us-story-main-data .us-title .us-related-task a{border-left:1px solid #b8b8b8;padding:0 .2rem;-webkit-transition:color .3s linear;transition:color .3s linear}.us-story-main-data .us-title .us-related-task a:hover{color:#72a114}.us-story-main-data .us-title .us-related-task a:first-child{border:0}.us-story-main-data .us-title .block-description-title{color:#fff;margin-right:.5rem}.us-story-main-data .us-title .block-description{color:#fff;display:inline-block;margin-right:5rem}.us-story-main-data .loading-spinner{max-height:1.5rem;max-width:1.5rem}.blocked-warning{margin-bottom:1rem}.blocked-warning .blocked{color:red;line-height:2.5rem;margin-bottom:.5rem}.blocked-warning .icon{vertical-align:middle}.blocked-warning .block-description{color:#444;margin:0}.issue-nav{position:absolute;right:1rem;top:1rem}.duty-content{position:relative}.duty-content:hover .view-description .edit{opacity:1;top:-1.5rem;-webkit-transition:all .2s linear;transition:all .2s linear}.duty-content:hover .view-description .editable{background:#f5f5f5;cursor:pointer}.duty-content:hover .view-description .no-description{color:#444}.duty-content.wysiwyg{overflow:visible}.duty-content .no-description{color:#b8b8b8}.duty-content textarea{background:#fff;height:10rem}.duty-content .save-container{position:absolute;right:1rem;top:.2rem}.duty-content .save-container:hover{opacity:.3;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.duty-content .save-container .loading-spinner{max-height:1.5rem;max-width:1.5rem}.duty-content .edit{color:#444}.duty-content .view-description .edit{background:#f5f5f5;left:0;opacity:0;padding:.2rem .5rem;position:absolute;top:0;-webkit-transition:all .2s linear;transition:all .2s linear}.duty-content .edit-description .save{top:.4rem}.duty-content .edit-description .edit{position:absolute;right:2.5rem;top:.4rem;-webkit-transition:all .2s linear;transition:all .2s linear}.comment-list{padding:1rem}.us-detail-status{color:#72a114;vertical-align:middle}.us-detail-progress-bar{background:#444;height:26px;margin-bottom:1rem;position:relative}.us-detail-progress-bar .current-progress{background:#9dce0a;height:26px;left:0;position:absolute;top:0;width:60%}.us-detail-progress-bar .tasks-completed{color:#fff;left:10px;position:absolute;top:2px}.points-per-role{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative}.points-per-role>li{border-right:1px solid rgba(68,68,68,.3);color:rgba(68,68,68,.3);display:inline-block;-webkit-flex-basis:18%;-ms-flex-preferred-size:18%;flex-basis:18%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin:.5rem .1rem;position:relative;text-align:center;-webkit-transition:color .3s linear;transition:color .3s linear;width:18%}.points-per-role>li.active{color:#72a114}.points-per-role>li:first-child{opacity:1}.points-per-role>li:last-child{border:0}.points-per-role .points{display:block;text-align:center}.points-per-role .role{display:inline-block;max-width:90%;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap}.points-per-role .popover{background:#050505;color:#fff;display:none;left:35%;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.points-per-role .popover a{border-bottom:1px solid #444;color:#fff;padding:10px 2px}.points-per-role .popover a:last-child{border:0}.points-per-role .popover a:hover{-webkit-transition:color .3s linear;transition:color .3s linear}.points-per-role .popover:after{background:#050505;content:'';height:15px;left:10px;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.points-per-role .popover li{display:inline-block;width:23%}.points-per-role .popover a{display:block;text-align:center}.points-per-role .popover a.active,.points-per-role .popover a:hover{background:#9dce0a;color:#fff}.points-per-role .popover.fix{background:#050505;color:#fff;display:none;left:-160px;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.points-per-role .popover.fix a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.points-per-role .popover.fix a:last-child{border:0}.points-per-role .popover.fix a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.points-per-role .popover.fix:after{background:#050505;content:'';height:15px;left:90%;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.duty-data-container{margin-bottom:1rem}.duty-data-container .duty-data{margin-bottom:.5rem}.duty-data-container .duty-data:last-child{margin:0}.duty-data-container .duty-data div{background:#e8e8e8;padding:.5rem 1rem .5rem .5rem;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.duty-data-container .duty-data .clickable:hover{background:#dcdcdc;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.duty-data-container .level{display:inline-block;margin-right:.5rem;vertical-align:top}.duty-data-container .level-name{color:#c2c2c2;float:right}.us-detail-settings{margin-top:2rem}.us-detail-settings .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center;width:100%}.us-detail-settings .button-gray,.us-detail-settings .button-gray:hover{background:#b8b8b8}.us-detail-settings .button-gray.editable:hover{background:#444;cursor:pointer}.us-detail-settings .button-gray.active{background:#72a114}.us-detail-settings .item-block.editable:hover{background:red;cursor:pointer}.us-detail-settings .button-red.active,.us-detail-settings .button-red:hover{background:red}.us-detail-settings label.editable{cursor:pointer}.us-detail-settings label+input{display:none}.us-detail-settings span.button-gray,.us-detail-settings span.button-gray:hover{background:#b8b8b8}.us-detail-settings span.button-gray.active,.us-detail-settings span.button-gray:hover.active{background:#555}.us-detail-settings span.button-red,.us-detail-settings span.button-red:hover{background:#ff8282}.us-detail-settings span.button-red.active,.us-detail-settings span.button-red:hover.active{background:red}.us-status .type-data{position:relative}.us-status .type-data .pop-type{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .type-data .pop-type a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .type-data .pop-type a:last-child{border:0}.us-status .type-data .pop-type a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .type-data .pop-type:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .severity-data{position:relative}.us-status .severity-data .pop-severity{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .severity-data .pop-severity a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .severity-data .pop-severity a:last-child{border:0}.us-status .severity-data .pop-severity a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .severity-data .pop-severity:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .priority-data{position:relative}.us-status .priority-data .pop-priority{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .priority-data .pop-priority a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .priority-data .pop-priority a:last-child{border:0}.us-status .priority-data .pop-priority a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .priority-data .pop-priority:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.us-status .status-data{position:relative}.us-status .status-data .pop-status{background:#050505;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.us-status .status-data .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.us-status .status-data .pop-status a:last-child{border:0}.us-status .status-data .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.us-status .status-data .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.admin-membership header:after{clear:both;content:'';display:table}.admin-membership header a{float:right}.admin-roles p{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-roles header{position:relative}.admin-roles h1{margin-bottom:0}.admin-roles p{color:#b8b8b8}.project-values-options{margin-bottom:1rem;text-align:right}.project-colors .new-color{float:right}.project-colors .colors-table{margin-top:1rem}.project-colors .project-colors-options:after{clear:both;content:'';display:table}.kanban .kanban-settings{float:right}.kanban .burndown-container{display:none}.kanban .list-filters{margin-bottom:1rem}.issues .filters-bar{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:260px}.issues .filters-inner{opacity:1;padding:2em 1em}.wiki .remove{font-size:.8rem;color:#b8b8b8}.wiki .remove:hover span{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}.wiki .remove:hover .icon{color:red;-webkit-transition:color .2s linear;transition:color .2s linear}.wiki .remove .icon{color:#b8b8b8;margin-right:.2rem}.wiki-content{margin-bottom:2rem;position:relative}.wiki-content .view-wiki-content:hover .wysiwyg{background:#f5f5f5;cursor:pointer}.wiki-content .view-wiki-content:hover .edit{opacity:1;top:-1.5rem;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .view-wiki-content .edit{background:#f5f5f5;left:0;opacity:0;padding:.2rem .5rem;position:absolute;top:0;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .edit-wiki-content .icon:hover{color:#444;opacity:.3;-webkit-transition:all .2s linear;transition:all .2s linear}.wiki-content .edit-wiki-content .preview-icon{position:absolute;right:3.5rem}.wiki-content .edit-wiki-content .action-container{position:absolute;right:1rem;top:.3rem}.wiki-content .edit-wiki-content .edit{position:absolute;right:3.5rem;top:.4rem}.wysiwyg{margin-bottom:2rem}.wysiwyg textarea{background:#fff;max-height:none}.save-wiki{float:right}.team h2{margin:1rem 0}.team h2 span:last-child{color:#72a114}.button,.button-github,a.button-bulk,a.button-bulk .icon{font-size:1rem}.button-github .icon,.trans-button{font-size:1.2rem}.button,.button-github,.trans-button,a.button-bulk{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.button,.button-github,a.button-bulk{display:inline-block;padding:7px 40px 6px;-webkit-transition:background .3s linear;transition:background .3s linear;text-transform:uppercase}.button-github:hover,.button:hover,a.button-bulk:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.loading.button span,.loading.button-github span,a.loading.button-bulk span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.button .icon,.button-github .icon,a.button-bulk .icon{margin-right:.3rem}.trans-button{text-transform:uppercase}.trans-button.active,.trans-button:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.trans-button .icon{margin-right:.3rem}a.button-green{background:#72a114;color:#fff;vertical-align:middle}a.button-green.active,a.button-green:hover{background:#9dce0a}a.button-green span{color:#fff}.button-gray,a.button-gray{background:#585858}.button-gray:hover,a.button-gray:hover{background:#9dce0a;color:#fff}.button-gray span,a.button-gray span{color:#fff}a.button-blackish{background:#050505;color:#f5f5f5}a.button-blackish:hover{background:#879b89;color:#fff}a.button-blackish span{color:#fff}a.button-red{background:#ff8282}a.button-red:hover{background:red;color:#fff}a.button-red span{color:#fff}a.button-orange{background:#d98a0b}a.button-orange:hover{background:#f4a423;color:#fff}a.button-orange span{color:#fff}a.button-block{background:#fff;color:red}a.button-block:hover{background:#ff8282;color:#fff}a.button-bulk{background:#72a114;font-size:22px;margin-left:2px;padding:.3rem .5rem;vertical-align:middle}a.button-bulk .icon{color:#fff;margin-right:0}a.button-bulk:hover{background:#9dce0a;-webkit-transition:background .3s linear;transition:background .3s linear}.button-github{background:#444;vertical-align:middle}.button-github .icon{color:#fff;margin-right:.5rem;vertical-align:text-bottom}.button-github:hover{background:#000;-webkit-transition:background .3s linear;transition:background .3s linear}.avatar img{border:2px solid #fff;border-radius:8%;width:100%}.summary .description{font-size:.8rem}.summary .icon{font-size:1.2rem}.large-summary .icon,.summary .number{font-size:2rem}.summary .description{font-family:opensans-regular,Arial,Helvetica,sans-serif}.summary .number{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.summary{background:#444;color:#fff;margin-bottom:2rem;padding:1em}.summary:after{clear:both;content:'';display:table}.summary ul{display:inline-block;margin:0;padding:0}.summary li{display:inline-block;margin-right:1rem}.summary .data{float:left;margin-right:1em;margin-top:4px}.summary .data .number{color:#9dce0a;top:0}.summary .icon{float:left}.summary .number{float:left;margin-right:.3rem;position:relative;top:5px}.summary .description{float:left;line-height:.9rem}.summary-progress-bar{background:#f5f5f5;float:left;height:30px;margin-bottom:0;margin-right:10px;padding:3px;position:relative;width:15%}.summary-progress-bar .current-progress{background:#9dce0a;height:24px}.summary-progress-bar .defined-points{background:#ff8282;height:24px;position:absolute;width:calc(100% - 6px)}.summary-progress-bar .project-points-progress{background:#fff;height:24px;position:absolute}.summary-progress-bar .closed-points-progress{background:#9dce0a;height:24px;position:absolute}.large-summary ul{border-right:1px solid #f5f5f5;margin-right:1rem;vertical-align:top}.large-summary ul:last-of-type{border:0;margin:0}.large-summary .icon{margin-right:.4rem}.large-summary .icon.icon-stats{color:#555;float:right;-webkit-transition:color .3s linear;transition:color .3s linear}.large-summary .icon.icon-stats:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.large-summary .icon.icon-stats.active{color:#9dce0a}.large-summary .icon.icon-stats.active:hover{color:#555;-webkit-transition:color .3s linear;transition:color .3s linear}.tags-block .add-tag-text,.tags-block .tag{font-size:.8rem}.tags-block .icon-plus{font-size:1.2rem}.tag{background:#f5f5f5;color:#444;display:inline-block;margin-right:.5rem;padding:.2rem .5rem;text-align:center}.tag .icon-delete{color:#b8b8b8;margin-left:1rem}.tag .icon-delete:hover{color:red}.ui-autocomplete{background:#fff;border:1px solid #b8b8b8;z-index:99910}.ui-autocomplete .ui-state-focus{background:#9dce0a}.ui-helper-hidden-accessible{display:none}.tags-block .tags-container{display:inline-block}.tags-block input{padding:.4rem;width:14rem}.tags-block .tag{margin:0 .5rem .5rem 0;padding:.5rem}.tags-block .add-tag{color:#b8b8b8}.tags-block .add-tag:hover{color:#9dce0a}.single-filter{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;cursor:pointer;display:block;height:32px;margin-bottom:1rem;opacity:.5;position:relative}.single-filter:after{clear:both;content:'';display:table}.single-filter.active,.single-filter.selected,.single-filter:hover{color:#444;opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.single-filter .name,.single-filter .number{padding:8px 10px}.single-filter .name{background:#dcdcdc;display:block;width:100%}.single-filter .number{background:#c2c2c2;position:absolute;right:0;top:0}.single-filter .icon-delete{color:#444;position:absolute;right:.5rem;top:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.single-filter .icon-delete:hover{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-task .task-assigned,.taskboard-task .taskboard-text,.taskboard-task .taskboard-user-avatar a{font-size:.8rem}.taskboard-task .icon-drag-h,.taskboard-task .icon-edit,.taskboard-task .icon-iocaine{font-size:1.2rem}.taskboard-task .icon-drag-h{font-size:2rem}.taskboard-task .task-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.taskboard-task{background:#fff8e4;border:1px solid #f1e8cd;box-shadow:none;cursor:move;margin:.2rem;min-height:7rem;position:relative}.taskboard-task:hover .icon-drag-h,.taskboard-task:hover .icon-edit{color:#e4d6ad;display:block;opacity:1;-webkit-transition:color .3s linear,opacity .3s linear;transition:color .3s linear,opacity .3s linear}.taskboard-task.ui-sortable-helper{box-shadow:1px 1px 15px rgba(0,0,0,.4);-webkit-transition:box-shadow .3s linear;transition:box-shadow .3s linear}.taskboard-task.ui-sortable-placeholder{background:#444}.taskboard-task.blocked{background:red;border:1px solid #c00;color:#fff}.taskboard-task.blocked a,.taskboard-task.blocked span{color:#fff}.taskboard-task .taskboard-tagline{border-color:#f1e8cd;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:.6rem}.taskboard-task .taskboard-tag{border-top:.3rem solid #f1e8cd;-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;height:.6rem;z-index:100}.taskboard-task .taskboard-task-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.taskboard-task .taskboard-user-avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:55px}.taskboard-task .taskboard-user-avatar a{display:block;text-align:center}.taskboard-task .taskboard-user-avatar img{margin:0 auto}.taskboard-task .taskboard-user-avatar img:hover{border:2px solid #72a114;-webkit-transition:border .3s linear;transition:border .3s linear}.taskboard-task .taskboard-user-avatar figcaption{color:#e0cd91;display:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.taskboard-task .iocaine img{-webkit-filter:hue-rotate(150deg) saturate(200%);filter:hue-rotate(150deg) saturate(200%)}.taskboard-task .icon-iocaine{background:#000;border-radius:5px;color:#fff;left:.2rem;padding:.1rem;position:absolute;top:1rem}.taskboard-task .task-assigned{color:#e4d6ad;display:block}.taskboard-task .task-num{color:#444;margin-right:.5em}.taskboard-task .taskboard-text{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10;padding:0 .5rem 0 1rem;word-wrap:break-word}.taskboard-task .icon{-webkit-transition:color .3s linear,opacity .3s linear;transition:color .3s linear,opacity .3s linear}.taskboard-task .icon-drag-h,.taskboard-task .icon-edit{bottom:.5rem;color:#f1e8cd;opacity:0;position:absolute}.taskboard-task .icon-drag-h:hover,.taskboard-task .icon-edit:hover{color:#e4d6ad}.taskboard-task .icon-edit{right:1rem}.taskboard-task .icon-drag-h{cursor:move;right:45%}.task-drag{box-shadow:1px 1px 15px 6px rgba(0,0,0,.1)}.kanban-task .avatar a,.kanban-task .task-assigned,.kanban-task .task-text,.kanban-task-maximized .task-archived p,.kanban-task-maximized .task-points,.kanban-task-minimized .task-archived{font-size:.8rem}.kanban-task-minimized .icon-drag-h{font-size:1rem}.kanban-task .icon-drag-h,.kanban-task .icon-edit{font-size:1.2rem}.kanban-task-maximized .icon-drag-h{font-size:2rem}.kanban-task .task-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.kanban-task{background:#fff8e4;cursor:move;margin:.2rem;position:relative}.kanban-task:last-child{margin-bottom:0}.kanban-task:hover .icon-drag-h,.kanban-task:hover .icon-edit{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.kanban-task.ui-sortable-helper{box-shadow:1px 1px 15px rgba(0,0,0,.4);-webkit-transition:box-shadow .3s linear;transition:box-shadow .3s linear}.kanban-task.blocked{background:red;border:1px solid #c00;color:#fff}.kanban-task.blocked a,.kanban-task.blocked span{color:#fff}.kanban-task .kanban-tagline{border-color:#f1e8cd;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:.6rem}.kanban-task .kanban-tag{border-color:#f1e8cd;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;height:.6rem}.kanban-task .kanban-task-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.kanban-task .avatar a{text-align:center}.kanban-task .avatar img{margin:0 auto}.kanban-task .avatar img:hover{border:2px solid #72a114;-webkit-transition:border .3s linear;transition:border .3s linear}.kanban-task .avatar .assigned-to{color:#e0cd91;display:none;overflow:hidden;position:relative;text-overflow:ellipsis;top:-6px;white-space:nowrap;width:50px}.kanban-task .task-assigned{color:#e4d6ad;display:block}.kanban-task .task-text{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10;padding:0 .5rem 0 .8rem;word-wrap:break-word}.kanban-task .task-num{color:#444;margin-right:.3rem}.kanban-task .icon-drag-h,.kanban-task .icon-edit{color:#f1e8cd;opacity:0;position:absolute;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.kanban-task .icon-drag-h:hover,.kanban-task .icon-edit:hover{color:#e0cd91;-webkit-transition:color .3s linear;transition:color .3s linear}.kanban-task-maximized .kanban-task-inner{padding:1rem 1rem 2rem}.kanban-task-maximized .task-archived{background:#e8e8e8;padding:.5rem;text-align:left;-webkit-transition:background .3s linear;transition:background .3s linear}.kanban-task-maximized .task-archived:hover{background:#e1e1e1;-webkit-transition:background .3s linear;transition:background .3s linear}.kanban-task-maximized .task-archived .task-archived-text{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.kanban-task-maximized .task-archived span{color:#b8b8b8}.kanban-task-maximized .task-archived p{color:#b8b8b8;margin:0}.kanban-task-maximized .task-archived p:last-child{color:#555;margin:.5rem 0;text-align:center}.kanban-task-maximized .avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:55px}.kanban-task-maximized .task-name{word-wrap:break-word}.kanban-task-maximized .icon-edit{bottom:.2rem;right:.5rem}.kanban-task-maximized .icon-drag-h{bottom:.2rem;cursor:move;right:45%}.kanban-task-maximized .task-points{color:#e0cd91;margin:0}.kanban-task-maximized .task-points span{display:inline-block}.kanban-task-maximized .task-points span:first-child{padding-right:.2rem}.kanban-task-maximized .kanban-tag{border-top:.3rem solid}.kanban-task-minimized .kanban-task-inner{padding:0 .3rem}.kanban-task-minimized .task-archived{background:#e8e8e8;padding:.3rem;text-align:left}.kanban-task-minimized .task-archived .task-archived-text{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.kanban-task-minimized .task-archived span{color:#b8b8b8}.kanban-task-minimized .task-archived .task-name{display:inline-block;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kanban-task-minimized .task-archived p{color:#b8b8b8;margin:0}.kanban-task-minimized .task-archived p:last-child{display:none}.kanban-task-minimized .avatar{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;width:55px}.kanban-task-minimized .task-num{vertical-align:top}.kanban-task-minimized .task-name{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:70%}.kanban-task-minimized .task-points{display:none}.kanban-task-minimized .icon-drag-h,.kanban-task-minimized .icon-edit{top:1.4rem}.kanban-task-minimized .icon-edit{bottom:.2rem;right:1rem}.kanban-task-minimized .icon-drag-h{cursor:move;right:.1rem;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.kanban-task-minimized .kanban-tag{border-top:.2rem solid}.notification-light .warning{font-size:1.2rem}.notification-message .warning{font-size:2rem}.notification-message-error .icon-notification-error,.notification-message-success .icon-notification-success{font-size:3rem}.notification-light .warning,.notification-message .warning{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.notification-message{background:rgba(184,184,184,.95);color:#fff;opacity:0;padding:1rem;position:fixed;top:0;-webkit-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%);width:100%;z-index:99920}.notification-message.inactive{-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-message.active{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-message .text{display:inline-block;margin-left:.5rem;width:80%}.notification-message .text p{margin:0}.notification-message .warning{color:#fff;line-height:2.4rem}.notification-message .icon-delete{color:#fff;position:absolute;right:1rem;top:1rem}.notification-message-success{background:rgba(157,206,10,.9)}.notification-message-success .icon-notification-success{display:inline;vertical-align:sub}.notification-message-error{background:rgba(255,0,0,.9)}.notification-message-error .icon-notification-error{display:inline;vertical-align:sub}.notification-light{background:rgba(184,184,184,.95);color:#fff;left:calc(50% - 200px);padding:1rem 1rem .2rem;position:absolute;top:0;-webkit-transform:translateY(-100%);-ms-transform:translateY(-100%);transform:translateY(-100%);width:400px;z-index:99999}.notification-light.inactive{-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-light.active{-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .6s ease-in-out;transition:all .6s ease-in-out}.notification-light .text{display:inline-block;margin-left:.5rem;width:80%}.notification-light .warning{color:#fff;line-height:2.4rem}.notification-light .icon-delete{color:#fff;position:absolute;right:1rem}.notification-message-light-error{background:rgba(255,0,0,.95)}.basic-table{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%}.basic-table .row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #ebebeb;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding:.3rem 0;text-align:left;width:100%}.basic-table .row .width-1{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.basic-table .row .width-2{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:2;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2}.basic-table .row .width-3{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.basic-table .row .width-4{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:4;-webkit-flex-grow:4;-ms-flex-positive:4;flex-grow:4}.basic-table .row .width-5{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:5;-webkit-flex-grow:5;-ms-flex-positive:5;flex-grow:5}.basic-table .row .width-6{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6}.basic-table .row .width-7{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:7;-webkit-flex-grow:7;-ms-flex-positive:7;flex-grow:7}.basic-table .row .width-8{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8}.basic-table .row:last-child{border-bottom:0}.paginator{margin:2rem 0}.paginator ul{margin-left:1rem}.paginator li{display:inline-block}.paginator .active span,.paginator .dots,.paginator a{background:#b8b8b8;color:#fff;margin-right:.1rem;padding:.5rem 1rem;-webkit-transition:all .3s linear;transition:all .3s linear}.paginator a:hover{background:#879b89;color:#fff;-webkit-transition:all .3s linear;transition:all .3s linear}.paginator .active span{background:#9dce0a}.paginator .dots{background:0 0;color:#b8b8b8}.v-pagination-list{overflow:hidden}.v-pagination-next,.v-pagination-previous{background-color:#585858;color:#f5f5f5;display:block;padding:.1rem 0;text-align:center;visibility:hidden;width:100%}.v-pagination-next:hover,.v-pagination-previous:hover{background-color:#2c2c2c;-webkit-transition:background .3s linear;transition:background .3s linear}.watchers .watcher-name{font-size:.8rem}.watchers .watchers-header .icon,.watchers .watchers-header .title{font-size:1.2rem}.watchers .watchers-header .title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.watchers{margin-top:1rem}.watchers .watchers-header{border-bottom:2px solid #b8b8b8;padding:.5rem;position:relative}.watchers .watchers-header .title{text-transform:uppercase}.watchers .watchers-header .icon{position:absolute;right:1rem}.watchers .watchers-header.no-watchers{border-bottom:0}.watchers .watcher-single{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:0 0;border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.5rem;vertical-align:middle}.watchers .watcher-single:last-child{border:0}.watchers .watcher-single:hover .icon-delete{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.watchers .watcher-name{color:#444;-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;margin-left:1rem;position:relative}.watchers .watcher-avatar{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.watchers .icon-delete{opacity:0;position:absolute;right:.5rem;top:0;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.watchers .icon-delete:hover{color:red;-webkit-transition:color .3s ease-in;transition:color .3s ease-in}.level{background-color:#b8b8b8;border-radius:9px;height:18px;margin:0 auto;width:18px}.us-created-by .created-by .created-date,.us-created-by .created-by .created-title{font-size:.8rem}.us-created-by .created-by .created-user{font-size:1.2rem}.us-created-by{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:1rem;margin-top:.5rem;position:relative}.us-created-by .user-avatar{-webkit-flex-basis:40px;-ms-flex-preferred-size:40px;flex-basis:40px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.us-created-by .user-avatar img{border-radius:8%;width:100%}.us-created-by .created-by{-webkit-flex-basis:70px;-ms-flex-preferred-size:70px;flex-basis:70px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;margin-left:.5rem}.us-created-by .created-by .created-date,.us-created-by .created-by .created-title{color:#b8b8b8;display:block}.us-created-by .created-by .created-user{color:#72a114;cursor:default}.us-created-by .created-by .created-user.editable{cursor:pointer}.wysiwyg code,.wysiwyg pre{font-size:.8rem}.wysiwyg h2{font-size:1.2rem}.wysiwyg h1{font-size:2rem;font-family:opensans-regular,Arial,Helvetica,sans-serif}.wysiwyg h2,.wysiwyg h3{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.wysiwyg{line-height:1.4rem;overflow:auto}.wysiwyg h1{line-height:2.5rem;text-transform:uppercase}.wysiwyg h2{margin-bottom:.5rem;text-transform:uppercase}.wysiwyg h3{text-transform:uppercase}.wysiwyg ol,.wysiwyg ul{list-style-position:inside;margin-left:1rem}.wysiwyg ul{list-style-type:disc}.wysiwyg dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.wysiwyg dl dd{margin-bottom:16px;padding:0 16px}.wysiwyg a{color:#72a114}.wysiwyg a:hover{color:#9dce0a}.wysiwyg p{line-height:1.4rem;margin-bottom:1rem}.wysiwyg code,.wysiwyg pre{background:#f5f5f5;direction:ltr;font-family:'courier new',monospace;margin-bottom:1rem;unicode-bidi:embed;white-space:pre}.wysiwyg pre{line-height:1.4rem;padding:.5rem}.wysiwyg table{border:1px solid #b8b8b8;margin-bottom:1rem}.wysiwyg table tbody tr:last-child{border-bottom:0}.wysiwyg tr{border-bottom:#b8b8b8 1px solid}.wysiwyg th{border-right:#b8b8b8 1px solid;padding:1rem 1rem 1rem .5rem}.wysiwyg th:last-child{border-right:0}.wysiwyg td{border-right:#b8b8b8 1px solid;padding:.5rem}.wysiwyg td:last-child{border-right:0}.wysiwyg img{max-width:100%}.select-color a{font-size:.8rem}.select-color input{font-size:1rem}.select-color,.select-color input{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.select-color{background:#050505;color:#fff;display:none;left:50px;list-style-type:none;margin:0;position:absolute;top:0;width:323px;z-index:99;border-radius:0 10px 10px 0;padding:15px}.select-color a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.select-color a:last-child{border:0}.select-color a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.select-color:after{background:#050505;content:'';height:15px;left:-7px;position:absolute;top:13px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.select-color li{float:left;margin:0 .5rem .5rem 0}.select-color li:nth-child(7n){margin-right:0}.select-color li:nth-last-child(-n+7){margin-bottom:0}.select-color .color{background-color:#b8b8b8;border-radius:2px;cursor:pointer;height:35px;width:35px}.select-color ul{float:left;margin-bottom:1rem}.select-color input{background-color:#fcfcfc;width:243px}.select-color input::-webkit-input-placeholder{color:#555}.select-color input::-moz-placeholder{color:#555}.select-color input:-moz-placeholder{color:#555}.select-color input:-ms-input-placeholder{color:#555}.select-color .selected-color{background:#b8b8b8;border-radius:2px;cursor:pointer;float:right;height:40px;width:40px}.loader p{font-size:1.2rem}.loader{background-color:#fff;bottom:0;display:none;height:100%;left:0;opacity:0;position:fixed;right:0;top:0;width:100%;z-index:-100}.loader .container{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;width:100%}.loader p{color:#555;text-align:center}.loader.active{background-color:rgba(255,255,255,.95);display:block;opacity:1;z-index:99900}.loading-bar{-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.loading-bar .item{-webkit-animation-duration:5s;animation-duration:5s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:loadBar;animation-name:loadBar;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;background:#555;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;height:5px}.loading-bar .item-0{-webkit-animation-delay:0s;animation-delay:0s;background:#bbe831}.loading-bar .item-1{-webkit-animation-delay:1s;animation-delay:1s;background:#237400}.loading-bar .item-2{-webkit-animation-delay:2s;animation-delay:2s;background:#e43050}.loading-bar .item-3{-webkit-animation-delay:3s;animation-delay:3s;background:#810061}.loading-bar .item-4{-webkit-animation-delay:4s;animation-delay:4s;background:#618000}a.help{color:#b8b8b8;position:absolute;right:1rem;top:1rem;-webkit-transition:color .2s linear;transition:color .2s linear}a.help:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.beta{left:0;position:absolute;top:0;z-index:9999}.markItUpHeader ul{background:#f5f5f5;padding:.3rem}.markItUpHeader ul li{display:inline-block;float:none}.markItUpHeader ul li a{opacity:.8}.markItUpHeader ul li a:hover{opacity:.3;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.markItUpHeader ul .preview-icon{position:absolute;right:2.5rem}.markItUpContainer{padding:0}.markdown{position:relative}.preview .actions{background:#f5f5f5;margin-top:.5rem;min-height:2rem;padding:.3rem}a.help-button,a.help-markdown{font-size:.8rem;color:#b8b8b8}a.help-button:hover span,a.help-markdown:hover span{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}a.help-button:hover .icon,a.help-markdown:hover .icon{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}a.help-button .icon,a.help-markdown .icon{color:#b8b8b8;margin-right:.2rem}.duty-assigned-to .assigned-to .assigned-title{font-size:.8rem}.duty-assigned-to .assigned-to .user-assigned{font-size:1.2rem}.duty-assigned-to .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;max-height:1rem;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.duty-assigned-to{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-top:1rem;position:relative}.duty-assigned-to:hover .assigned-to .icon-delete{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.duty-assigned-to .loading-spinner{margin:0 auto;max-width:2rem}.duty-assigned-to .user-avatar{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.duty-assigned-to .user-avatar img{border-radius:8%;width:100%}.duty-assigned-to .assigned-to{-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;margin-left:1rem;margin-top:15px}.duty-assigned-to .assigned-to .assigned-title{color:#b8b8b8;display:block}.duty-assigned-to .assigned-to .user-assigned{color:#72a114;cursor:default;line-height:1.5rem}.duty-assigned-to .assigned-to .user-assigned.editable{cursor:pointer}.duty-assigned-to .assigned-to .user-assigned .icon{vertical-align:top}.duty-assigned-to .assigned-to .assigned-name{max-width:80%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block}.duty-assigned-to .assigned-to .icon-delete{color:#b8b8b8;opacity:0;position:absolute;right:0;top:0}.duty-assigned-to .assigned-to .icon-delete:hover{color:red}.user .popover a{font-size:.8rem}.logo-container span,.main-nav a .item{font-size:1.2rem}.main-nav a .icon{font-size:2rem}.menu{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.menu{background-image:url(../images/menu.png);background-position:left bottom;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;height:100%;padding:0 .3rem;position:fixed;text-transform:uppercase;width:90px;z-index:999}.logo-container{cursor:pointer;padding:15px 15px 10px}.logo-container img,.logo-container object,.logo-container svg{height:50px;width:50px}.logo-container span{color:#fff;display:block;margin-top:-5px;text-align:center}.logo-container sup{display:block;line-height:1rem}.main-nav{list-style:none;padding:0;position:relative;text-align:center}.main-nav li{margin-bottom:1rem}.main-nav a{color:#fff;display:block;text-align:center}.main-nav a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.main-nav a span{display:block}.main-nav a .icon{line-height:2.2rem}.main-nav .active{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.user{bottom:1rem;padding:0 10px;position:absolute;width:80px}.user .popover{background:#050505;bottom:0;color:#fff;display:none;left:60px;list-style-type:none;margin:0;padding:10px;position:absolute;width:150px;z-index:99}.user .popover a{border-bottom:1px solid #444;display:block;padding:10px 2px}.user .popover a:last-child{border:0}.user .popover:after{background:#050505;bottom:25px;content:'';height:15px;left:-6px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.user .popover a{color:#fff;text-align:left;text-transform:none}.user .popover a:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.user img{margin:0 5px 10px;width:80%}.user img:hover{border-color:#9dce0a;-webkit-transition:border-color .3s linear;transition:border-color .3s linear}.user .user-settings{position:relative}.user .settings{text-align:center}.user .settings a{color:#f5f5f5;margin-right:.5rem}.user .settings a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.projects-nav-overlay p{font-size:1rem}.projects-list a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.projects-nav-overlay{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover}.projects-nav{background-color:#232323;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;height:100%;left:0;overflow:hidden;padding:2rem 1rem;position:fixed;top:0;-webkit-transform:translate3d(-300px,0,0);transform:translate3d(-300px,0,0);width:300px;z-index:99}.projects-nav form{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.projects-nav h1{color:#fff;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-bottom:2rem;text-align:center}.projects-nav input{background-color:#555;color:#f5f5f5}.projects-nav .icon-search{position:absolute;right:.7rem;top:.7rem}.projects-nav ul{left:0;margin-bottom:0;margin-top:1rem;position:relative;top:0;width:100%}.projects-nav .projects-pagination{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;margin-top:1rem}.projects-nav .create-project-button-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-top:1rem}.projects-nav .create-project-button-wrapper .create-project-button{-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;margin-right:.2rem;text-align:center}.projects-nav .create-project-button-wrapper .import-project-button{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-left:.5rem;padding-right:.5rem;text-align:center}.projects-nav .create-project-button-wrapper .import-project-button .icon{color:#444;margin:0}.projects-nav .v-pagination-next,.projects-nav .v-pagination-previous{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.projects-list a{color:#f5f5f5;display:block;padding:1rem;position:relative;text-transform:uppercase;width:100%}.projects-list a.active,.projects-list a:hover{background-color:#555;color:#72a114;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.projects-list a.active .icon,.projects-list a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.projects-list a .project-name{display:block;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.projects-list .icon{color:#f5f5f5;opacity:0;position:absolute;right:1rem;top:1rem}.projects-list li{border-bottom:2px solid #555}.projects-nav-overlay{bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;width:100%;z-index:99900}.projects-nav-overlay .container{left:-200px;margin:15% auto 0;opacity:0;position:relative;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);width:150px}.projects-nav-overlay p{color:#9dce0a;padding-top:20px;text-align:center}.lightbox-add-member .help-text,.lightbox-delete-account .newsletter input+label,.lightbox-generic-form .points-per-role .popover a,.lightbox-sprint-add-edit .delete-sprint,.markdown-preview a{font-size:.8rem}.lightbox-generic-form label,.lightbox-select-user .more-watchers,.markdown-preview a{font-size:1rem}.lightbox .close,.lightbox-add-member .icon,.lightbox-ask-choice .subtitle,.lightbox-delete-account .subtitle,.lightbox-delete-project .subtitle,.lightbox-generic-ask .subtitle,.lightbox-generic-loading .progress-bar-wrapper .progress{font-size:1.2rem}.lightbox-ask-choice .subtitle,.lightbox-delete-account .subtitle,.lightbox-delete-project .subtitle,.lightbox-generic-ask .subtitle,.lightbox-generic-form label,.lightbox-generic-loading .progress-bar-wrapper .progress,.lightbox-select-user .more-watchers,.markdown-preview a{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.lightbox-delete-account .newsletter input+label,.lightbox-generic-form .points-per-role .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.lightbox-generic-loading .progress-bar-wrapper .progress{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.lightbox{background:rgba(255,255,255,.95);bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;z-index:99910}.lightbox .close{position:absolute;right:2rem;top:2rem}.open.lightbox{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:1;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.close.lightbox{opacity:0;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.lightbox .title{text-align:center}.lightbox input,.lightbox select,.lightbox textarea{margin-bottom:1rem}.lightbox textarea{resize:vertical}.lightbox .button-gray,.lightbox .button-green{display:block;padding:12px;text-align:center}.lightbox-generic-form label,.markdown-preview a{display:inline-block;padding:7px 40px 6px;-webkit-transition:background .3s linear;transition:background .3s linear;text-transform:uppercase}.lightbox-generic-form label:hover,.markdown-preview a:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.lightbox-generic-form label.loading span,.markdown-preview a.loading span{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.lightbox-generic-form label .icon,.markdown-preview a .icon{margin-right:.3rem}.lightbox .loading-spinner,.lightbox-generic-loading .spin img{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;max-height:1rem;max-width:1rem;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.markdown-preview{display:inline-block;margin-bottom:.5rem}.markdown-preview a{color:#b8b8b8;padding:3px 20px}.markdown-preview a:first-child{border-right:1px solid #b8b8b8}.markdown-preview a:hover{color:#444;-webkit-transition:color .2s linear;transition:color .2s linear}.markdown-preview .active{color:#444}.lightbox-generic-form form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-generic-form fieldset{position:relative}.lightbox-generic-form textarea{margin-bottom:1rem;max-height:9rem;min-height:7rem}.lightbox-generic-form label{border:1px solid #b8b8b8;color:#444;cursor:pointer;display:block;padding:7px 30px;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form label:hover span{color:#fff}.lightbox-generic-form label span{color:#444;vertical-align:middle}.lightbox-generic-form .settings{-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start;-webkit-box-align:stretch;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;margin-bottom:1rem}.lightbox-generic-form .settings fieldset{-webkit-flex-basis:30%;-ms-flex-preferred-size:30%;flex-basis:30%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem;text-align:center}.lightbox-generic-form .settings fieldset:last-child{margin:0}.lightbox-generic-form .settings .iocaine:hover,.lightbox-generic-form .settings .requirement:hover{background:#9dce0a;border:1px solid #9dce0a;color:#fff;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form .settings .blocked{padding:8px 30px}.lightbox-generic-form .settings .blocked:hover{background:#ff8282;border:1px solid #ff8282;color:#fff;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.lightbox-generic-form .settings .client-requirement input:checked+label,.lightbox-generic-form .settings .iocaine-flag input:checked+label,.lightbox-generic-form .settings .team-requirement input:checked+label{background:#9dce0a;color:#fff}.lightbox-generic-form .settings .blocking-flag input:checked+label{background:red;color:#fff}.lightbox-generic-form .settings input{display:none}.lightbox-generic-form .points-per-role .popover{background:#050505;color:#fff;display:none;left:35%;list-style-type:none;margin:0;padding:10px;position:absolute;top:105%;width:200px;z-index:99}.lightbox-generic-form .points-per-role .popover a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.lightbox-generic-form .points-per-role .popover a:last-child{border:0}.lightbox-generic-form .points-per-role .popover a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-generic-form .points-per-role .popover:after{background:#050505;content:'';height:15px;left:10px;position:absolute;top:-5px;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.lightbox-generic-bulk form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-generic-bulk textarea{margin-bottom:1rem;max-height:12rem;min-height:15rem}.lightbox-search form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;max-width:600px}.lightbox-search input{margin-bottom:1rem}.lightbox-add-member .add-member-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:.5rem}.lightbox-add-member .add-member-wrapper:last-child{margin-bottom:0}.lightbox-add-member .add-member-wrapper fieldset{position:relative}.lightbox-add-member .add-member-wrapper fieldset:first-child{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.lightbox-add-member .add-member-wrapper fieldset:last-child{-webkit-flex-basis:200px;-ms-flex-preferred-size:200px;flex-basis:200px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:.5rem}.lightbox-add-member .extra-text{margin-top:1rem}.lightbox-add-member input,.lightbox-add-member select{margin-bottom:0}.lightbox-add-member select{width:80%}.lightbox-add-member .icon{margin-left:.5rem}.lightbox-add-member .icon-delete:hover{color:red}.lightbox-add-member .button{margin-top:1rem}.lightbox-add-member .help-text{padding:.5rem 1rem}.lightbox-add-member .checksley-error-list{right:.5rem}.lightbox-add-member .checksley-error-list li{display:none}.lightbox-add-member .checksley-error-list li:first-child{display:block}.lightbox-sprint-add-edit form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-flex-flow:0;-ms-flex-flow:0;flex-flow:0;max-width:600px}.lightbox-sprint-add-edit .last-sprint-name{color:#555;opacity:1;position:absolute;right:1rem;top:.7rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.lightbox-sprint-add-edit .last-sprint-name.disappear{opacity:0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.lightbox-sprint-add-edit .dates{margin-bottom:1rem}.lightbox-sprint-add-edit .dates div{float:left;margin-right:1%;position:relative;width:49%}.lightbox-sprint-add-edit .dates div:last-child{margin:0;width:50%}.lightbox-sprint-add-edit .delete-sprint{color:#444;display:block;margin-top:1rem;text-align:right}.lightbox-sprint-add-edit .delete-sprint a{color:#b8b8b8;margin-left:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-sprint-add-edit .delete-sprint a:hover{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.lightbox-generic-ask form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-flex-flow:0;-ms-flex-flow:0;flex-flow:0;max-width:420px}.lightbox-generic-ask .message,.lightbox-generic-ask .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-generic-ask .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-generic-ask .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-generic-ask .options a:first-child{margin-right:.5rem}.lightbox-ask-choice{text-align:center}.lightbox-ask-choice form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.lightbox-ask-choice .question,.lightbox-ask-choice .subtitle{display:block;line-height:1.5rem;text-align:center}.lightbox-ask-choice .replacement,.lightbox-ask-choice .replacement span{display:block}.lightbox-ask-choice .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-ask-choice .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-ask-choice .options a:first-child{margin-right:.5rem}.lightbox-delete-account form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-delete-account .question,.lightbox-delete-account .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-delete-account .newsletter{margin-top:1rem;text-align:center}.lightbox-delete-account .newsletter input{margin-right:.5rem}.lightbox-delete-account .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-delete-account .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-delete-account .options a:first-child{margin-right:.5rem}.lightbox-delete-project form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-delete-project .question,.lightbox-delete-project .subtitle{display:block;line-height:2rem;text-align:center}.lightbox-delete-project .options{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-delete-project .options a{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:8px 0;text-align:center}.lightbox-delete-project .options a:first-child{margin-right:.5rem}.lightbox-generic-error section,.lightbox-generic-loading section,.lightbox-generic-success section{-webkit-flex-basis:500px;-ms-flex-preferred-size:500px;flex-basis:500px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;width:500px}.lightbox-generic-error h2,.lightbox-generic-loading h2,.lightbox-generic-success h2{line-height:2rem}.lightbox-generic-error p,.lightbox-generic-loading p,.lightbox-generic-success p{text-align:center}.lightbox-generic-loading .spin{margin:1rem auto;width:5rem}.lightbox-generic-loading .spin img{max-height:100%;max-width:100%;width:100%}.lightbox-generic-loading .progress-bar-wrapper{background:#e8e8e8;height:30px;margin-bottom:1rem;padding:3px;position:relative}.lightbox-generic-loading .progress-bar-wrapper .bar{background:#9dce0a;height:24px;position:absolute;-webkit-transition:width .1s linear;transition:width .1s linear}.lightbox-generic-loading .progress-bar-wrapper .progress{background:#e8e8e8;bottom:35px;color:#555;padding:.3rem;position:absolute;-webkit-transition:left .1s linear;transition:left .1s linear}.lightbox-create-issue form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:600px}.lightbox-create-issue .fieldset-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.lightbox-create-issue .fieldset-row fieldset{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem;width:30%}.lightbox-create-issue .fieldset-row fieldset:last-child{margin:0}.lightbox-create-issue textarea{margin-bottom:1rem;max-height:12rem;min-height:8rem}.lightbox-block .form{-webkit-flex-basis:420px;-ms-flex-preferred-size:420px;flex-basis:420px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:420px}.lightbox-block textarea{margin-bottom:1rem;max-height:12rem;min-height:8rem}.lightbox-select-user .form{-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:600px}.lightbox-select-user .watchers{margin-top:1rem;min-height:440px}.lightbox-select-user .watchers .watcher-name{-webkit-box-flex:12;-webkit-flex-grow:12;-ms-flex-positive:12;flex-grow:12}.lightbox-select-user .watcher-single{position:relative}.lightbox-select-user .watcher-single.active,.lightbox-select-user .watcher-single:hover{background:#edfad4;cursor:pointer}.lightbox-select-user .watcher-single:hover{-webkit-transition:background .3s linear;transition:background .3s linear}.lightbox-select-user .watcher-single.active .icon{opacity:1;right:1rem;top:1.3rem}.lightbox-select-user .more-watchers{padding:.5rem;text-align:center}.lb-create-edit-userstory .points-per-role{margin-bottom:1rem}.lb-create-edit-userstory .points-per-role li{margin:.5rem .1rem}.colors-table .table-header{font-size:1rem}.colors-table .icon,.colors-table .icon-check-square{font-size:1.2rem}.colors-table .table-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif;border-bottom:2px solid #b8b8b8}.colors-table .table-header:hover{background:0 0}.colors-table .table-header .row{padding-left:50px}.colors-table .row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1rem}.colors-table .row:hover .options-column{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.colors-table .row.edition,.colors-table .row.new-value{padding-left:50px}.colors-table .row.hidden{display:none}.colors-table .row.edition .current-color{cursor:pointer}.colors-table .row .color-column{-webkit-flex-basis:60px;-ms-flex-preferred-size:60px;flex-basis:60px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100px;position:relative}.colors-table .row .is-archived-column,.colors-table .row .is-closed-column,.colors-table .row .options-column,.colors-table .row .status-wip-limit{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.colors-table .row .status-name{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6;padding:0 10px;position:relative}.colors-table .row .status-name span{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.colors-table .row .status-slug{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:6;-webkit-flex-grow:6;-ms-flex-positive:6;flex-grow:6;padding:0 10px}.colors-table .row .options-column{max-width:100px;opacity:0;text-align:right}.colors-table .row .is-archived-column{max-width:130px;padding:0 0 0 10px;text-align:center}.colors-table .row .is-closed-column{max-width:130px;text-align:center}.colors-table .row .status-wip-limit{max-width:130px;padding:0 0 0 10px;text-align:center}.colors-table .row-edit .options-column{opacity:1}.colors-table .table-main{border-bottom:1px solid #b8b8b8}.colors-table .table-main .row:hover{background:#f6fceb;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.colors-table .current-color{background-color:#b8b8b8;border-radius:2px;height:40px;width:40px}.colors-table .icon{color:#b8b8b8;margin-right:1rem}.colors-table .icon:hover{color:#72a114}.colors-table .icon-delete:hover{color:red}.colors-table .icon-check-square{color:#72a114}.category-config .icon{font-size:2rem}.category-config{border-bottom:1px solid #b8b8b8}.category-config:first-child{border-top:1px solid #b8b8b8}.category-config .resume{-webkit-box-align:space-between;-webkit-align-items:space-between;-ms-flex-align:space-between;align-items:space-between;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:1rem;position:relative}.category-config .resume-title{width:280px}.category-config .count{color:#b8b8b8;float:left;padding-right:5px}.category-config .summary-role{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;width:280px}.category-config .summary-role .role-summary-single{background:#b8b8b8;display:inline-block;height:20px;margin-right:.1rem;width:15px}.category-config .summary-role .role-summary-single.active{background:#72a114}.category-config .summary-role .role-summary-single.inactive{background:#555}.category-config .icon{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;text-align:right}.category-config .category-items{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow:overflow-y;background-color:#f5f5f5;width:100%}.category-config .category-items.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:400px}.category-config .category-items .items-container{padding:1rem}.category-config .category-item{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #fcfcfc;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem .5rem .5rem 2rem}.category-config .category-item:last-child{border-bottom:0}.add-attach span,.more-attachments,.single-attachment{font-size:.8rem}.attachments-header .attachments-title,.single-attachment .editable-attachment-comment{font-size:1rem}.attachments-header .icon,.single-attachment .attachment-settings .editable-settings,.single-attachment .attachment-settings .settings,.single-attachment .icon-delete{font-size:1.2rem}.attachments-header .attachments-title,.single-attachment .attachment-name{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.attachments{margin-bottom:2rem}.attachments-header{-webkit-align-content:space-between;-ms-flex-line-pack:justify;align-content:space-between;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.attachments-header .attachments-title{color:#444}.attachments-header .attachments-num,.attachments-header .attachments-text{margin-right:.1rem}.attachments-header .icon{color:#444;cursor:pointer}.attachments-header .icon:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.single-attachment{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem 0 .5rem 1rem;position:relative}.single-attachment:hover .attachment-settings .settings{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.single-attachment.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.single-attachment.deprecated,.single-attachment.deprecated .attachment-name a{color:#b8b8b8}.single-attachment.sortable-placeholder{background:#f5f5f5;height:40px}.single-attachment .attachment-name{max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-flex-basis:35%;-ms-flex-preferred-size:35%;flex-basis:35%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-right:1rem}.single-attachment .attachment-name .icon{margin-right:.5rem}.single-attachment .attachment-size{color:#b8b8b8;-webkit-flex-basis:15%;-ms-flex-preferred-size:15%;flex-basis:15%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.5rem}.single-attachment .attachment-comments,.single-attachment .editable-attachment-comment{-webkit-flex-basis:35%;-ms-flex-preferred-size:35%;flex-basis:35%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.single-attachment .attachment-comments span,.single-attachment .editable-attachment-comment span{color:#555}.single-attachment .attachment-settings{-webkit-flex-basis:15%;-ms-flex-preferred-size:15%;flex-basis:15%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.single-attachment .attachment-settings .editable-settings,.single-attachment .attachment-settings .settings{color:#b8b8b8;display:block;position:absolute}.single-attachment .attachment-settings .editable-settings:hover,.single-attachment .attachment-settings .settings:hover{color:#72a114}.single-attachment .attachment-settings .settings{opacity:0;top:.5rem}.single-attachment .attachment-settings .editable-settings{opacity:1;top:1rem}.single-attachment .attachment-settings .icon-edit,.single-attachment .attachment-settings .icon-floppy{right:3.5rem}.single-attachment .attachment-settings .icon-delete{right:2rem}.single-attachment .attachment-settings .icon-delete:hover{color:red}.single-attachment .attachment-settings .icon-drag-v{cursor:move;right:0}.single-attachment .icon-delete{color:#b8b8b8}.single-attachment .icon-delete:hover{color:red}.single-attachment .editable-attachment-deprecated{padding-left:1rem}.single-attachment .editable-attachment-deprecated span{color:#b8b8b8}.single-attachment .editable-attachment-deprecated input{margin-right:.2rem;vertical-align:middle}.single-attachment .editable-attachment-deprecated input:checked+span{color:#444}.single-attachment .percentage{background:rgba(114,161,20,.1);bottom:0;height:40px;left:0;position:absolute;top:0;width:45%}.more-attachments{border-bottom:1px solid #b8b8b8;display:block;padding:1rem 0 1rem 1rem}.more-attachments span{color:#b8b8b8}.more-attachments .more-attachments-num{color:#72a114;margin-left:.5rem}.more-attachments:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.add-attach{cursor:pointer;overflow:hidden;position:relative}.add-attach input{display:none}.add-attach span{color:#b8b8b8}.related-tasks-body .pop-status a,.related-tasks-body .row{font-size:.8rem}.related-tasks-body .task-name input,.related-tasks-header .related-tasks-title{font-size:1rem}.related-tasks-body .iocaine .icon-iocaine,.related-tasks-body .iocaine:hover .icon-iocaine,.related-tasks-body .task-settings a,.related-tasks-header .icon{font-size:1.2rem}.related-tasks-body .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.related-tasks-header .related-tasks-title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.related-tasks{margin-bottom:2rem;position:relative}.related-tasks-header{-webkit-align-content:space-between;-ms-flex-line-pack:justify;align-content:space-between;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.related-tasks-header .icon{color:#444;cursor:pointer}.related-tasks-header .icon:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.related-tasks-body{width:100%}.related-tasks-body .row{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.5rem 0 .5rem .5rem;position:relative;text-align:left;width:100%}.related-tasks-body .row:hover{background:0 0}.related-tasks-body .row:hover .task-settings{opacity:1;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .row:last-child{border:0}.related-tasks-body .row .tasks{-webkit-flex-basis:78%;-ms-flex-preferred-size:78%;flex-basis:78%;-webkit-box-flex:10;-webkit-flex-grow:10;-ms-flex-positive:10;flex-grow:10}.related-tasks-body .row .assigned-to,.related-tasks-body .row .status{-webkit-flex-basis:10%;-ms-flex-preferred-size:10%;flex-basis:10%}.related-tasks-body .related-task-create-form{padding:0}.related-tasks-body .related-task-create-form.active{padding:.5rem 0 .5rem .5rem}.related-tasks-body .status{position:relative;text-align:left}.related-tasks-body .status:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.related-tasks-body .status .not-clickable:hover{color:#444}.related-tasks-body .status .popover a{text-align:left;width:100%}.related-tasks-body .status .popover .point{text-align:center}.related-tasks-body .status .icon{color:#b8b8b8;margin-left:.2rem;opacity:0}.related-tasks-body .pop-status{background:#050505;color:#fff;display:none;left:40%;list-style-type:none;margin:0;padding:10px 1rem 10px 10px;position:absolute;top:0;width:200px;z-index:99}.related-tasks-body .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.related-tasks-body .pop-status a:last-child{border:0}.related-tasks-body .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.related-tasks-body .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.related-tasks-body .pop-status.fix{bottom:0;top:auto}.related-tasks-body .task-name{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:relative}.related-tasks-body .task-name a{display:inline-block;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.related-tasks-body .task-name input{margin-right:1rem;padding:3px;width:85%}.related-tasks-body .task-name.loading{margin:0;padding:8px;text-align:center;width:100%}.related-tasks-body .task-name.loading span{-webkit-animation:loading .5s linear,spin 1s linear infinite;animation:loading .5s linear,spin 1s linear infinite}.related-tasks-body .blocked,.related-tasks-body .blocked:hover{background:#ff8282;color:#fff}.related-tasks-body .blocked a,.related-tasks-body .blocked:hover a{color:#fff!important}.related-tasks-body .blocked .icon,.related-tasks-body .blocked .icon:hover,.related-tasks-body .blocked a:hover,.related-tasks-body .blocked:hover .icon,.related-tasks-body .blocked:hover .icon:hover,.related-tasks-body .blocked:hover a:hover{color:#fff}.related-tasks-body .icon-iocaine{display:none}.related-tasks-body .iocaine,.related-tasks-body .iocaine:hover{background:rgba(157,206,10,.3)}.related-tasks-body .iocaine .icon-iocaine,.related-tasks-body .iocaine:hover .icon-iocaine{display:inline-block;margin-right:.5rem;vertical-align:top}.related-tasks-body .task-settings{margin:0 0 0 2rem;opacity:0;position:absolute;right:0;top:.1rem;width:10%}.related-tasks-body .task-settings a{color:#b8b8b8;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .task-settings a:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.related-tasks-body .assigned-to{position:relative;text-align:left}.related-tasks-body .task-assignedto{position:relative}.related-tasks-body .task-assignedto.editable{cursor:pointer}.related-tasks-body .task-assignedto:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.related-tasks-body .task-assignedto figcaption{max-width:50%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.related-tasks-body .task-assignedto .icon{opacity:0;position:absolute;right:.5rem;top:.5rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.related-tasks-body .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.related-tasks-body .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px;height:35px;width:35px}.related-tasks-body .avatar figcaption{margin-left:.5rem}.activity-single .comment-restore,.activity-single .date,.activity-single .deleted-comment,.activity-single.deleted-comment,.change-entry .activity-fromto,.more-activity,.more-comments,.show-more-comments{font-size:.8rem}.activity-single .deleted-comment .comment-body p,.activity-single.deleted-comment .comment-body p{font-size:1rem}.history-tabs li{font-size:1.2rem}.history-tabs{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.change-entry .activity-changed{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.add-comment .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.history{margin-bottom:1rem}.changes-title{display:block;padding:.5rem}.changes-title:hover .icon{color:#72a114;-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear}.changes-title .icon{color:#444;float:right;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.change-entry{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.change-entry:last-child{border-bottom:0}.change-entry .activity-changed,.change-entry .activity-fromto{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.history-tabs{border-bottom:3px solid #b8b8b8;padding:.5rem 0}.history-tabs li{display:inline-block}.history-tabs li:first-child{border-right:1px solid #b8b8b8}.history-tabs a{color:#b8b8b8;padding:0 2rem;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.history-tabs a.active{color:#444}.history-tabs a:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.history-tabs .icon{margin-right:.5rem}.add-comment:after{clear:both;content:'';display:table}.add-comment.active .button-green{display:block}.add-comment.active textarea{height:6rem;-webkit-transition:height .3s ease-in;transition:height .3s ease-in}.add-comment.active .help-markdown{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.add-comment.active .preview-icon{opacity:1;position:absolute;right:1rem}.add-comment textarea{background:#fff;height:5rem;margin-bottom:.5rem;min-height:41px}.add-comment .help-markdown{opacity:0}.add-comment .save-comment{color:#fff;float:right}.add-comment .button-green{display:none}.add-comment .edit,.add-comment .preview-icon{position:absolute;right:1rem}.add-comment .preview-icon{opacity:0}.add-comment .loading-spinner{max-height:1rem;max-width:1rem}.show-more-comments{border-bottom:1px solid #b8b8b8;border-top:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem 0 1rem 1rem}.show-more-comments:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.more-comments{border-bottom:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem}.more-comments .prev-comments-num{color:#72a114;margin-left:.5rem}.comment-list.activeanimation .comment-single.ng-enter:last-child,.comment-list.activeanimation .comment-single.ng-leave:last-child{-webkit-transition:all .3s ease-in;transition:all .3s ease-in}.comment-list.activeanimation .comment-single.ng-enter:last-child,.comment-list.activeanimation .comment-single.ng-leave.ng-leave-active:last-child{opacity:0}.comment-list.activeanimation .comment-single.ng-enter.ng-enter-active:last-child,.comment-list.activeanimation .comment-single.ng-leave:last-child{opacity:1}.activity-single{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:2rem 0;position:relative}.activity-single:hover .comment-delete,.activity-single:hover .comment-restore{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.activity-single:first-child{margin-top:0}.activity-single:last-child{border-bottom:0}.activity-single .deleted-comment,.activity-single.deleted-comment{color:#b8b8b8;padding:.5rem}.activity-single .deleted-comment a,.activity-single.deleted-comment a{color:#b8b8b8;margin-left:.3rem}.activity-single .deleted-comment a:hover,.activity-single.deleted-comment a:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single .deleted-comment img,.activity-single.deleted-comment img{-webkit-filter:grayscale(100%);filter:grayscale(100%);opacity:.5}.activity-single .deleted-comment .comment-body,.activity-single.deleted-comment .comment-body{display:none;margin:.2rem 0 .5rem}.activity-single .comment-restore{color:#b8b8b8;position:absolute;right:0;top:.4rem}.activity-single .comment-restore .icon{vertical-align:baseline}.activity-single .comment-restore:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single .username{color:#72a114;margin-bottom:.5rem}.activity-single .activity-user{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.activity-single .activity-user img{max-width:70px;width:100%}.activity-single .activity-username{color:#72a114;margin-bottom:.5rem}.activity-single .activity-content{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:20;-webkit-flex-grow:20;-ms-flex-positive:20;flex-grow:20}.activity-single .changes{background:#f5f5f5}.activity-single .changes .change-entry{display:none}.activity-single .changes .change-entry.active{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.activity-single .date{color:#b8b8b8;margin-left:1rem}.activity-single .wysiwyg{margin-bottom:0}.activity-single .comment-delete{color:red;opacity:0;position:absolute;right:0;top:2rem;-webkit-transition:all .2s linear;transition:all .2s linear}.activity-single .comment-delete:hover{color:#ff8282;-webkit-transition:color .2s linear;transition:color .2s linear}.activity-single.activity .change-entry{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.more-activity{border-bottom:1px solid #b8b8b8;color:#b8b8b8;display:block;padding:1rem}.more-activity .prev-activity-num{color:#72a114;margin-left:.5rem}.wizard-create-project p{font-size:.8rem}.wizard-create-project .close{font-size:1.2rem}.wizard-create-project .create-step1 input+label .icon{font-size:3rem}.wizard-create-project{bottom:0;display:none;left:0;opacity:0;position:fixed;right:0;top:0;z-index:99910}.wizard-create-project .close{position:absolute;right:2rem;top:2rem}.open.wizard-create-project{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:1;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.close.wizard-create-project{opacity:0;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.wizard-create-project .title{text-align:center}.wizard-create-project input,.wizard-create-project select,.wizard-create-project textarea{margin-bottom:1rem}.wizard-create-project textarea{resize:vertical}.wizard-create-project .button-gray,.wizard-create-project .button-green{display:block;padding:12px;text-align:center}.wizard-create-project .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;max-height:1rem;max-width:1rem;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.wizard-create-project{background:url(/images/invitation_bg.jpg) center center no-repeat;background-size:cover;color:#fff;text-align:center}.wizard-create-project form{width:500px}.wizard-create-project .title{width:100%}.wizard-create-project h1,.wizard-create-project p{color:#fff}.wizard-create-project h1{line-height:1.5rem}.wizard-create-project p{opacity:.8}.wizard-create-project input,.wizard-create-project select,.wizard-create-project textarea{background:rgba(255,255,255,.7)}.wizard-create-project input::-webkit-input-placeholder,.wizard-create-project select::-webkit-input-placeholder,.wizard-create-project textarea::-webkit-input-placeholder{color:#444}.wizard-create-project input::-moz-placeholder,.wizard-create-project select::-moz-placeholder,.wizard-create-project textarea::-moz-placeholder{color:#444}.wizard-create-project input:-moz-placeholder,.wizard-create-project select:-moz-placeholder,.wizard-create-project textarea:-moz-placeholder{color:#444}.wizard-create-project input:-ms-input-placeholder,.wizard-create-project select:-ms-input-placeholder,.wizard-create-project textarea:-ms-input-placeholder{color:#444}.wizard-create-project .close{color:#fff}.wizard-create-project .close:hover{color:#ff8282}.wizard-create-project .wizard-step{-webkit-animation:formSlide .4s ease-in-out;animation:formSlide .4s ease-in-out;-webkit-animation-direction:alternate-reverse;animation-direction:alternate-reverse;display:none}.wizard-create-project .wizard-step.active{-webkit-animation:formSlide .4s ease-in-out;animation:formSlide .4s ease-in-out}.wizard-create-project .wizard-step.active.create-step1,.wizard-create-project .wizard-step.active.create-step2,.wizard-create-project .wizard-step.active.create-step3{display:block}.wizard-create-project .wizard-action div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.wizard-create-project .wizard-action a{color:#fff;display:inline-block;-webkit-flex-basis:40%;-ms-flex-preferred-size:40%;flex-basis:40%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.wizard-create-project .wizard-action a:first-child{margin-right:.5rem}.wizard-create-project .create-step1 .template-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.wizard-create-project .create-step1 fieldset{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.wizard-create-project .create-step1 fieldset:first-child{margin-right:.5rem}.wizard-create-project .create-step1 input{display:none}.wizard-create-project .create-step1 input:checked+label{background:rgba(157,206,10,.7);-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label{background:rgba(245,245,245,.7);cursor:pointer;display:block;margin-bottom:1rem;padding:1rem;text-align:center;-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label:hover{background:rgba(114,161,20,.7);-webkit-transition:background .3s ease-in;transition:background .3s ease-in}.wizard-create-project .create-step1 input+label .icon{color:#fff}.wizard-create-project .create-step1 h2{color:#fff;margin:.5rem 0 0;text-transform:uppercase}.wizard-create-project .create-step1 p{text-align:center}.wizard-create-project .progress-bar{bottom:0;height:.5rem;left:0;position:absolute;width:100%}.wizard-create-project .step1 .bar{-webkit-transition:width .6s ease-in-out;transition:width .6s ease-in-out;width:25%}.wizard-create-project .step1 .progress-state span:nth-child(1){color:#fff;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out;-webkit-transition-delay:.6s;transition-delay:.6s}.wizard-create-project .step2 .bar{-webkit-transition:width .6s ease-in-out;transition:width .6s ease-in-out;width:75%}.wizard-create-project .step2 .progress-state span:nth-child(1),.wizard-create-project .step2 .progress-state span:nth-child(2){color:#fff;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out;-webkit-transition-delay:.6s;transition-delay:.6s}.wizard-create-project .progress-state{position:absolute;width:100%}.wizard-create-project .progress-state span{color:rgba(255,255,255,.5);display:inline-block;margin-left:-100px;position:absolute;text-align:center;top:-2rem;-webkit-transition:all 1s ease-in;transition:all 1s ease-in;width:200px}.wizard-create-project .progress-state span:nth-child(1){left:25%}.wizard-create-project .progress-state span:nth-child(2){left:75%}.wizard-create-project .progress-bar-wrapper{background:rgba(255,255,255,.3);height:.5rem}.wizard-create-project .bar{background:rgba(157,206,10,.9);height:.5rem;left:0;position:absolute;top:0;width:0}.external-reference{font-size:.8rem}.blocked .external-reference{color:#fff}.blocked .external-reference a{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.blocked .external-reference a:hover{color:#ff8282}.external-reference{color:#b8b8b8;margin-top:.5rem}.external-reference a{border-left:1px solid #b8b8b8;padding:0 .2rem;-webkit-transition:color .3s linear;transition:color .3s linear}.external-reference a:hover{color:#72a114}.external-reference a:first-child{border:0}.home-project .welcome-user .logout,.home-projects-list .welcome-user .logout,.project-content p{font-size:.8rem}.all-projects li a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.home-project,.home-projects-list{background:url(/images/invitation_bg.jpg) center center no-repeat #000;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-size:cover;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;padding:0;position:fixed;top:0;width:100%}.home-project .welcome-user,.home-projects-list .welcome-user{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;position:absolute;right:1rem;top:1rem}.home-project .welcome-user p,.home-projects-list .welcome-user p{color:#f5f5f5;margin-bottom:0}.home-project .welcome-user p span:before,.home-projects-list .welcome-user p span:before{content:' '}.home-project .welcome-user .logout,.home-projects-list .welcome-user .logout{float:right}.home-project .welcome-user .logout:hover,.home-projects-list .welcome-user .logout:hover{color:#ff8282}.home-project .welcome-user .info,.home-projects-list .welcome-user .info{padding-right:1rem}.home-project .welcome-user img,.home-projects-list .welcome-user img{width:40px}.home-projects-wrapper{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:1200px}.home-projects-list-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.recent-projects{-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;max-width:800px}.recent-projects ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin:0;padding:0}.recent-projects a{height:100%;left:0;padding:1rem;position:absolute;top:0;width:100%}.recent-projects li{background-color:rgba(255,255,255,.5);color:#f5f5f5;-webkit-flex-basis:230px;-ms-flex-preferred-size:230px;flex-basis:230px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;height:130px;margin-bottom:1rem;margin-right:1rem;position:relative;-webkit-transition:background-color .3s linear;transition:background-color .3s linear;width:23.5%}.recent-projects li:hover{background-color:rgba(157,206,10,.5);cursor:pointer;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.recent-projects li:hover p{color:#b8b8b8;-webkit-transition:color .3s linear;transition:color .3s linear}.recent-projects h2{color:#f5f5f5;line-height:2rem}.recent-projects p{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.project-content h2{margin-bottom:.5rem}.project-content p{line-height:1rem}.all-projects{background-color:rgba(0,0,0,.5);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:1rem;max-height:422px;padding:1rem;width:285px}.all-projects h1{color:#f5f5f5;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;text-align:center}.all-projects .v-pagination-list{max-height:221px}.all-projects ul{left:0;margin-bottom:0;position:relative;top:0;width:100%}.all-projects li{border-bottom:2px solid #555}.all-projects li a{color:#f5f5f5;display:block;padding:1rem;text-transform:uppercase;width:100%}.all-projects li .active,.all-projects li a:hover{background-color:#555;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.all-projects .projects-pagination{width:100%}.all-projects .create-project-button-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-top:1rem}.all-projects .create-project-button-wrapper .create-project-button{-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8;margin-right:.2rem;text-align:center}.all-projects .create-project-button-wrapper .import-project-button{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-left:.5rem;padding-right:.5rem;text-align:center}.all-projects .create-project-button-wrapper .import-project-button .icon{color:#444;margin:0}.all-projects .button-green{color:#f5f5f5;text-align:center;width:100%}.all-projects .button-green:hover{color:#f5f5f5}.all-projects .v-pagination-next{margin-bottom:1rem}.home-project-info-list .info-text{font-size:.8rem}.home-project-info-list .info-num{font-size:2rem;font-family:opensans-semibold,Arial,Helvetica,sans-serif}.home-project-info-list{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.home-project-info-list li{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:1rem}.home-project-info-list .info-num{float:left;margin-right:.3rem;position:relative;top:5px}.home-project-info-list .info-text{float:left;line-height:.9rem}.project-data-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.project-data-container p{-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.project-data-container ul{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-data-container li{display:inline-block;margin-right:.1rem;width:10%}.project-data-container li figure{width:100%}.create-project .tagline{font-size:2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.create-project{background:url(/images/bg.png) center center no-repeat;background-size:cover;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;bottom:0;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:999}.create-project fieldset{margin-bottom:1rem}.create-project .create-project-container{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.create-project h1{color:#fff;text-align:center}.create-project .logo,.create-project .tagline{margin-bottom:1rem;text-align:center}.create-project .tagline{color:#fff;line-height:2rem;text-transform:uppercase}.create-project form{margin-bottom:2rem}.create-project input{background:#fff}.create-project input::-webkit-input-placeholder{color:#b8b8b8}.create-project input::-moz-placeholder{color:#b8b8b8}.create-project input:-moz-placeholder{color:#b8b8b8}.create-project input:-ms-input-placeholder{color:#b8b8b8}.create-project .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center}.create-project .button:hover{background:#9dce0a}.create-project a:hover{color:#fff}.issues-table .pop-status a,.issues-table .table-main{font-size:.8rem}.issues-table .title{font-size:1rem}.issues-table .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.issues-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.issues-table{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:2rem}.issues-table.empty{display:none}.issues-table .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.issues-table .row .icon{display:inline}.issues-table .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.issues-table .title{border-bottom:1px solid #b8b8b8}.issues-table .title:hover{background:0 0}.issues-table .title div{cursor:pointer}.issues-table .table-main{border-bottom:1px solid #ebebeb}.issues-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.issues-table .avatar img{width:35px}.issues-table .avatar figcaption{-webkit-flex-basis:60%;-ms-flex-preferred-size:60%;flex-basis:60%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-left:.5rem}.issues-table .level-field{-webkit-flex-basis:70px;-ms-flex-preferred-size:70px;flex-basis:70px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.issues-table .subject{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:7;-webkit-flex-grow:7;-ms-flex-positive:7;flex-grow:7;padding-right:1rem}.issues-table .subject span:first-child{margin-right:.5rem}.issues-table .assigned-field,.issues-table .created-field,.issues-table .issue-field{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem;position:relative;text-align:left}.issues-table .assigned-field{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:2;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2}.issues-table .issue-assignedto{cursor:pointer;position:relative}.issues-table .issue-assignedto:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.issues-table .issue-assignedto figcaption{max-width:60%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.issues-table .issue-assignedto .icon{opacity:0;position:absolute;right:0;top:.5rem;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.issues-table .pop-status{background:#050505;color:#fff;display:none;left:0;list-style-type:none;margin:0;padding:10px;position:absolute;top:20px;width:200px;z-index:99}.issues-table .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.issues-table .pop-status a:last-child{border:0}.issues-table .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.issues-table .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.issues-table .pop-status.fix{bottom:0;top:auto}.kanban-table-body .task-column .kanban-column-intro{font-size:.8rem}.kanban-table-body,.kanban-table-header .task-colum-name .icon{font-size:1rem}.kanban-table-header .task-colum-name{font-size:1.2rem}.kanban-table-body .task-column .kanban-column-intro{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.kanban-table{overflow:hidden;width:100%}.kanban-table .vfold.task-colum-name{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;opacity:.8;padding:.5rem 0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.kanban-table .vfold.task-colum-name .icon-bulk,.kanban-table .vfold.task-colum-name .icon-closed-eye,.kanban-table .vfold.task-colum-name .icon-open-eye,.kanban-table .vfold.task-colum-name .icon-plus,.kanban-table .vfold.task-colum-name .icon-vfold,.kanban-table .vfold.task-colum-name .icon-vunfold,.kanban-table .vfold.task-colum-name span{display:none}.kanban-table .vfold.task-colum-name .hunfold{margin:0}.kanban-table .vfold.task-colum-name,.kanban-table .vfold.task-column{-webkit-flex-flow:1;-ms-flex-flow:1;flex-flow:1;max-width:30px;min-height:2.5rem;min-width:30px;width:30px}.kanban-table .vfold .kanban-task{display:none}.kanban-table-header{margin-bottom:.5rem;position:relative;width:100%}.kanban-table-header .kanban-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;position:absolute}.kanban-table-header .task-colum-name{background:#f5f5f5;border-top:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin:0 10px 0 0;max-width:300px;padding:.5rem .5rem .5rem 1rem;position:relative;text-transform:uppercase}.kanban-table-header .task-colum-name:last-child{margin-right:0}.kanban-table-header .task-colum-name .icon{color:#b8b8b8;margin-right:.3rem;-webkit-transition:color .2s linear;transition:color .2s linear}.kanban-table-header .task-colum-name .icon:hover{color:#72a114}.kanban-table-header .task-colum-name .icon.hfold,.kanban-table-header .task-colum-name .icon.hunfold{display:inline-block;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.kanban-table-body{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;overflow-x:auto;width:100%}.kanban-table-body .task-column{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 10px 0 0;max-width:300px;overflow-y:auto;widows:300px}.kanban-table-body .task-column:last-child{margin-right:0}.kanban-table-body .task-column .kanban-column-intro{color:#b8b8b8;margin:1rem 2rem}.kanban-table-body .task-column .kanban-column-intro.active{color:#050505}.kanban-table-body .task-column .kanban-wip-limit{background:red;border-radius:2px;height:4px;margin:.5rem 0;padding:0}.kanban-table-body .kanban-uses-box{background:#f5f5f5}.kanban-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.search-filter a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.search-filter ul{border-bottom:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-bottom:.5rem}.search-filter li{margin-right:1rem}.search-filter a{opacity:.2}.search-filter .active,.search-filter a:hover{color:#555;opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.search-filter .icon{margin-right:.4rem}.search-filter .name{padding-left:5px}.search-result-table .table-main{font-size:.8rem}.search-result-table .title,.search-result-table .user-story-name .icon{font-size:1rem}.search-result-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.search-result-table .empty .title{border:0}.search-result-table .row{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem}.search-result-table .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.search-result-table .row .user-stories{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:5;-webkit-flex-grow:5;-ms-flex-positive:5;flex-grow:5;-webkit-flex-shrink:1;-ms-flex-negative:1;flex-shrink:1}.search-result-table .row .points,.search-result-table .row .status{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem;text-align:center}.search-result-table .row .assigned-to{-webkit-flex-basis:250px;-ms-flex-preferred-size:250px;flex-basis:250px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 1rem}.search-result-table .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.search-result-table .user-story-name input{vertical-align:top}.search-result-table .user-story-name span{display:inline-block;max-width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-result-table .user-story-name .icon{color:#b8b8b8}.search-result-table .user-story-name .icon:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.search-result-table .title{border-bottom:1px solid #b8b8b8}.search-result-table .title:hover{background:0 0}.search-result-table .table-main{border-bottom:1px solid #f5f5f5}.search-result-table .points,.search-result-table .status{position:relative}.search-result-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.search-result-table .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px}.search-result-table .avatar figcaption{display:inline-block;margin-left:.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-in input{background:#444;color:#fff}.search-in input::-webkit-input-placeholder{color:#b8b8b8}.search-in input::-moz-placeholder{color:#b8b8b8}.search-in input:-moz-placeholder{color:#b8b8b8}.search-in input:-ms-input-placeholder{color:#b8b8b8}.search-in .icon-search{color:#b8b8b8;position:absolute;right:.7rem;top:.7rem}.filters h2 .icon-arrow-right{font-size:1rem}.filters h2{font-size:1.2rem}.filters-inner .loading .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.filters h1{vertical-align:baseline}.filters h1 .icon{margin:0}.filters h1 a{vertical-align:baseline}.filters h2{margin-top:1rem}.filters h2 .icon-arrow-right{vertical-align:middle}.filters input{background:#444;color:#fff}.filters input::-webkit-input-placeholder{color:#b8b8b8}.filters input::-moz-placeholder{color:#b8b8b8}.filters input:-moz-placeholder{color:#b8b8b8}.filters input:-ms-input-placeholder{color:#b8b8b8}.filters .icon-search{color:#b8b8b8;position:absolute;right:.7rem;top:.7rem}.filters-inner{opacity:0;-webkit-transition:all .1s ease-in;transition:all .1s ease-in}.filters-inner .loading{margin:0;padding:8px;text-align:center;width:100%}.filters-inner .loading .loading-spinner{max-height:1rem;max-width:1rem}.filters-applied{margin-top:.5rem}.filters-applied .single-filter{margin-bottom:.5rem}.filters-step-cat .save-filters{color:#fff;display:block;text-align:center}.filters-step-cat .my-filter-name{background:#444;color:#f5f5f5;width:100%}.filters-step-cat .my-filter-name::-webkit-input-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name::-moz-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name:-moz-placeholder{color:#b8b8b8}.filters-step-cat .my-filter-name:-ms-input-placeholder{color:#b8b8b8}.filters-cats{margin-top:2rem}.filters-cats li{border-bottom:1px solid #b8b8b8;text-transform:uppercase}.filters-cats .custom-filters .title{color:#72a114}.filters-cats a{color:#444;display:block;padding:.5rem 0 .5rem .5rem;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.filters-cats a:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.filters-cats a:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.filters-cats .icon{color:#444;float:right;opacity:0;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.list-filters li a{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.list-filters{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-color:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:2rem;padding:.5rem 1rem}.list-filters ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:0}.list-filters li{margin-right:2rem}.list-filters li a{opacity:.4}.list-filters li .active,.list-filters li a:hover{color:#050505;opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.list-filters li .icon{padding-right:.5rem}.filter-tags{margin-top:2rem}.filter-tags .filter-tag{color:#fff;cursor:pointer;margin-bottom:1rem;opacity:.5;padding:.5rem 1rem;position:relative}.filter-tags .filter-tag.active{opacity:1}.filter-tags .tag-count{background:rgba(0,0,0,.3);padding:.5rem 1rem;position:absolute;right:0;top:0}.sprints .sprint .description{font-size:.5rem}.sprints .filter-closed-sprints,.sprints .sprint-table .column-us,.sprints .us-item-row .user-story-name{font-size:.8rem}.sprints .sprint .number,.sprints .sprint .sprint-date,.sprints .sprint-name a{font-size:1.2rem}.sprints .sprint .sprint-date,.sprints .sprint-name a{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.sprints .summary{background:#b8b8b8}.sprints .summary:after{clear:both;content:'';display:table}.sprints .summary ul{width:40%}.sprints .summary li{color:#444}.sprints .new-sprint{float:right}.sprints .new-sprint .button{padding:.5rem 1.5rem}.sprints .filter-closed-sprints{display:block;padding-bottom:1rem;text-align:center}.sprints .filter-closed-sprints .icon-kanban{margin-right:.3rem;vertical-align:middle}.sprints .filter-closed-sprints .load{display:inline-block;margin-left:.3rem;vertical-align:middle}.sprints .sprint-name a{max-width:90%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:inline-block;margin-right:3px}.sprints .sprint{margin-bottom:2rem;overflow:hidden}.sprints .sprint header{position:relative}.sprints .sprint:hover .icon-edit{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.sprints .sprint .icon{display:inline-block}.sprints .sprint .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprints .sprint .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprints .sprint .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprints .sprint .icon-edit{color:#b8b8b8;opacity:0;position:absolute;right:0;top:0;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in;vertical-align:baseline}.sprints .sprint .icon-edit:hover{color:#72a114;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.sprints .sprint .description{line-height:.6rem;margin-top:5px}.sprints .sprint .sprint-summary{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.sprints .sprint .sprint-date{color:#b8b8b8;-webkit-flex-flow:1;-ms-flex-flow:1;flex-flow:1}.sprints .sprint .sprint-points{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.sprints .sprint ul{float:right;margin:0}.sprints .sprint li{display:inline-block}.sprints .sprint li:first-child{margin-right:3px}.sprints .sprint-progress-bar{background:#b8b8b8;border-radius:2px;height:8px;margin-bottom:1rem;margin-top:.5rem;position:relative;width:100%}.sprints .sprint-progress-bar .current-progress{background:#72a114;border-radius:2px;height:8px;left:0;position:absolute;top:0;width:calc(30% - 4px)}.sprints .sprint-table .row{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5em 0;text-align:left;width:100%}.sprints .sprint-table .row:hover{background:#d7d7d7;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.sprints .sprint-table .row:last-child{border-bottom:0}.sprints .sprint-table .row.sortable-placeholder{background:#d7d7d7;height:40px}.sprints .sprint-table .row.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.sprints .sprint-table .column-us{-webkit-flex-flow:3;-ms-flex-flow:3;flex-flow:3;padding:0 4px}.sprints .sprint-table .us-name{max-width:250px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.sprints .sprint-table .us-name.closed{color:#c5c5c5}.sprints .sprint-table .us-name.blocked{color:red}.sprints .sprint-table .column-points{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 4px;text-align:right}.sprints .sprint-table .column-points.closed{color:#c5c5c5}.sprints .sprint-table .column-points.blocked{color:red}.sprints .button-gray{display:block;margin-top:1rem;text-align:center}.sprints .us-item-row .icon-drag-v,.sprints .us-item-row .popover,.sprints .us-item-row .status,.sprints .us-item-row .tags-block,.sprints .us-item-row .us-settings,.sprints .us-item-row input{display:none}.sprints .us-item-row .user-story-name{line-height:1rem;margin-top:5px}.sprint-old-open .sprint-name .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprint-old-open .sprint-name .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprint-old-open .sprint-name .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprint-closed .sprint-table{display:none}.sprint-closed .sprint-name .icon-arrow-up{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:baseline}.sprint-closed .sprint-name .icon-arrow-up.active{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s linear;transition:all .2s linear}.sprint-closed .sprint-name .icon-arrow-up:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.sprint-closed .description,.sprint-closed .number{color:#b8b8b8}.sprint-closed .sprint-progress-bar .current-progress{background:#9f9f9f}.sprint-closed .button-gray{background:#b8b8b8}.burndown{margin-bottom:2rem;width:100%}.backlog-table-body .doom-line span,.backlog-table-body .pop-points a,.backlog-table-body .pop-points-open a,.backlog-table-body .pop-role a,.backlog-table-body .pop-status a,.backlog-table-body .row,.backlog-table-body .tags-block .tag,.backlog-table-header .pop-points a,.backlog-table-header .pop-points-open a,.backlog-table-header .pop-role a,.backlog-table-header .pop-status a,.backlog-table-header .row{font-size:.8rem}.backlog-table-header .backlog-table-title{font-size:1rem}.backlog-table-body .icon-drag-v,.backlog-table-body .us-settings a{font-size:1.2rem}.backlog-table-body .doom-line span{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.backlog-table-body .pop-points,.backlog-table-body .pop-points-open,.backlog-table-body .pop-role,.backlog-table-body .pop-status,.backlog-table-header .pop-points,.backlog-table-header .pop-points-open,.backlog-table-header .pop-role,.backlog-table-header .pop-status{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.backlog-table-header .backlog-table-title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.backlog-table-body,.backlog-table-header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;width:100%}.backlog-table-body.show-tags .tags-block,.backlog-table-header.show-tags .tags-block{display:block}.backlog-table-body .row,.backlog-table-header .row{border-bottom:1px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:.5rem 0 .5rem .5rem;text-align:left;width:100%}.backlog-table-body .backlog-table-subtitle:hover,.backlog-table-body .backlog-table-title:hover,.backlog-table-body .row:hover,.backlog-table-header .backlog-table-subtitle:hover,.backlog-table-header .backlog-table-title:hover,.backlog-table-header .row:hover{background:0 0}.backlog-table-body .backlog-table-subtitle .user-stories,.backlog-table-body .backlog-table-title .user-stories,.backlog-table-body .row .user-stories,.backlog-table-header .backlog-table-subtitle .user-stories,.backlog-table-header .backlog-table-title .user-stories,.backlog-table-header .row .user-stories{width:100%}.backlog-table-body .backlog-table-subtitle .status,.backlog-table-body .backlog-table-title .status,.backlog-table-body .row .status,.backlog-table-header .backlog-table-subtitle .status,.backlog-table-header .backlog-table-title .status,.backlog-table-header .row .status{-webkit-flex-basis:150px;-ms-flex-preferred-size:150px;flex-basis:150px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.backlog-table-body .backlog-table-subtitle .points,.backlog-table-body .backlog-table-title .points,.backlog-table-body .row .points,.backlog-table-header .backlog-table-subtitle .points,.backlog-table-header .backlog-table-title .points,.backlog-table-header .row .points{-webkit-flex-basis:125px;-ms-flex-preferred-size:125px;flex-basis:125px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.backlog-table-body .points,.backlog-table-body .status,.backlog-table-header .points,.backlog-table-header .status{position:relative;text-align:right}.backlog-table-body .points .popover a,.backlog-table-body .status .popover a,.backlog-table-header .points .popover a,.backlog-table-header .status .popover a{text-align:left;width:100%}.backlog-table-body .points .popover .point,.backlog-table-body .status .popover .point,.backlog-table-header .points .popover .point,.backlog-table-header .status .popover .point{text-align:center}.backlog-table-body .points .icon,.backlog-table-body .status .icon,.backlog-table-header .points .icon,.backlog-table-header .status .icon{color:#b8b8b8;margin-left:.2rem}.backlog-table-body .pop-status,.backlog-table-header .pop-status{background:#050505;color:#fff;display:none;left:65%;list-style-type:none;margin:0;padding:10px 1rem 10px 10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-status a,.backlog-table-header .pop-status a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-status a:last-child,.backlog-table-header .pop-status a:last-child{border:0}.backlog-table-body .pop-status a:hover,.backlog-table-header .pop-status a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-status:after,.backlog-table-header .pop-status:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-status.fix,.backlog-table-header .pop-status.fix{bottom:0;top:auto}.backlog-table-body .pop-role,.backlog-table-header .pop-role{background:#050505;color:#fff;display:none;left:65%;list-style-type:none;margin:0;padding:10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-role a,.backlog-table-header .pop-role a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-role a:last-child,.backlog-table-header .pop-role a:last-child{border:0}.backlog-table-body .pop-role a:hover,.backlog-table-header .pop-role a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-role:after,.backlog-table-header .pop-role:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-role a.active,.backlog-table-header .pop-role a.active{background:#9dce0a;color:#fff}.backlog-table-body .pop-points,.backlog-table-header .pop-points{background:#050505;bottom:10px;color:#fff;display:none;left:30px;list-style-type:none;margin:0;padding:10px 3rem 10px 10px;position:absolute;width:150px;z-index:99}.backlog-table-body .pop-points a,.backlog-table-header .pop-points a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.backlog-table-body .pop-points a:last-child,.backlog-table-header .pop-points a:last-child{border:0}.backlog-table-body .pop-points a:hover,.backlog-table-header .pop-points a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-points:after,.backlog-table-header .pop-points:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-points-open,.backlog-table-header .pop-points-open{background:#050505;color:#fff;display:none;left:260px;list-style-type:none;margin:0;padding:10px;position:absolute;top:0;width:200px;z-index:99}.backlog-table-body .pop-points-open a,.backlog-table-header .pop-points-open a{border-bottom:1px solid #444;color:#fff;padding:10px 2px}.backlog-table-body .pop-points-open a:last-child,.backlog-table-header .pop-points-open a:last-child{border:0}.backlog-table-body .pop-points-open a:hover,.backlog-table-header .pop-points-open a:hover{-webkit-transition:color .3s linear;transition:color .3s linear}.backlog-table-body .pop-points-open:after,.backlog-table-header .pop-points-open:after{background:#050505;content:'';height:15px;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:0}.backlog-table-body .pop-points-open li,.backlog-table-header .pop-points-open li{display:inline-block;width:23%}.backlog-table-body .pop-points-open a,.backlog-table-header .pop-points-open a{display:block;text-align:center}.backlog-table-body .pop-points-open a.active,.backlog-table-body .pop-points-open a:hover,.backlog-table-header .pop-points-open a.active,.backlog-table-header .pop-points-open a:hover{background:#9dce0a;color:#fff}.backlog-table-header .backlog-table-title{border-bottom:2px solid #b8b8b8;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding-right:30px}.backlog-table-header .points{cursor:pointer}.backlog-table-header .header-points span{color:#b8b8b8}.backlog-table-body .row{border-bottom:1px solid #ebebeb;cursor:move;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;position:relative}.backlog-table-body .row:hover{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .row:hover .icon-drag-v,.backlog-table-body .row:hover .us-settings{opacity:1;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.backlog-table-body .row:last-child{border-bottom:0}.backlog-table-body .row.sortable-placeholder{background:#f5f5f5;height:40px}.backlog-table-body .row.ui-sortable-helper{background:#f6fceb;box-shadow:1px 1px 10px rgba(0,0,0,.1);-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .row .points .not-clickable:hover{color:#000;cursor:text}.backlog-table-body .row-selected{background:#f6fceb;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .user-story-name{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.backlog-table-body .user-story-name input{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin-right:1rem;vertical-align:super}.backlog-table-body .user-story-name input:checked+a{color:#9dce0a;-webkit-transition:color .2s ease-in;transition:color .2s ease-in}.backlog-table-body .user-story-name a{display:inline-block;-webkit-box-flex:20;-webkit-flex-grow:20;-ms-flex-positive:20;flex-grow:20;max-width:90%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.backlog-table-body .tags-block{display:none;margin-bottom:.3rem}.backlog-table-body .tags-block .tag{margin-right:.5rem;padding:.2rem .5rem}.backlog-table-body .blocked{background:#ff8282;border-bottom:1px solid #fff;color:#fff}.backlog-table-body .blocked:hover{background:red;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.backlog-table-body .blocked a{color:#fff!important}.backlog-table-body .blocked .icon,.backlog-table-body .blocked .icon:hover,.backlog-table-body .blocked a:hover{color:#fff}.backlog-table-body .doom-line{background:red;margin:.2rem 0;padding:.6rem 0;position:relative;width:100%}.backlog-table-body .doom-line span{color:#fff;position:absolute;right:.5rem;top:-3px}.backlog-table-body .icon-drag-v,.backlog-table-body .us-settings a{color:#b8b8b8;-webkit-transition:all .2s ease-in;transition:all .2s ease-in;width:30px}.backlog-table-body .icon-drag-v:hover,.backlog-table-body .us-settings a:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.backlog-table-body .us-settings{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 0 0 2rem;opacity:0}.backlog-table-body .icon-drag-v{cursor:move;opacity:0;padding:.1rem .5rem 0 0}.taskboard-userstory-box .points-value{font-size:.8rem}.taskboard-table-header .task-colum-name .icon{font-size:1rem}.taskboard-table-header .task-colum-name,.taskboard-userstory-box .us-title{font-size:1.2rem}.taskboard-userstory-box .us-title{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.taskboard-table-body .column-fold .taskboard-task,.taskboard-table-body .row-fold .taskboard-task{background:0 0;border:0;margin:0;min-height:0}.taskboard-table-body .column-fold .taskboard-task .taskboard-task-inner,.taskboard-table-body .row-fold .taskboard-task .taskboard-task-inner{padding:.2rem}.taskboard-table-body .column-fold .taskboard-task .taskboard-tagline,.taskboard-table-body .column-fold .taskboard-task .taskboard-text,.taskboard-table-body .row-fold .taskboard-task .taskboard-tagline,.taskboard-table-body .row-fold .taskboard-task .taskboard-text{display:none}.taskboard-table-body .column-fold .taskboard-task .avatar,.taskboard-table-body .row-fold .taskboard-task .avatar{height:35px;width:35px}.taskboard-table-body .column-fold .taskboard-task .icon,.taskboard-table-body .row-fold .taskboard-task .icon{display:none}.taskboard-table-body .column-fold .taskboard-task.ui-sortable-helper,.taskboard-table-body .row-fold .taskboard-task.ui-sortable-helper{box-shadow:none}.taskboard-table-body .column-fold .task-column,.taskboard-table-body .row-fold .task-column,.taskboard-table-body .task-column.column-fold,.taskboard-table-body .task-column.row-fold{-webkit-align-content:flex-start;-ms-flex-line-pack:start;align-content:flex-start;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.taskboard-table-body .column-fold .avatar-task-link,.taskboard-table-body .row-fold .avatar-task-link{display:block}.taskboard-table-body .column-fold .avatar-assigned-to,.taskboard-table-body .row-fold .avatar-assigned-to{display:none}.taskboard-table{overflow:hidden;width:100%}.taskboard-table-header{margin-bottom:.5rem;position:relative;width:100%}.taskboard-table-header .taskboard-table-inner{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;overflow:hidden;position:absolute}.taskboard-table-header .task-colum-name{background:#f5f5f5;border-top:3px solid #b8b8b8;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;margin:0 10px 0 0;max-width:300px;padding:.5rem 1rem;position:relative;text-transform:uppercase;width:300px}.taskboard-table-header .task-colum-name:last-child{margin-right:0}.taskboard-table-header .task-colum-name .icon{color:#b8b8b8;margin-right:.3rem;-webkit-transition:color .2s linear;transition:color .2s linear}.taskboard-table-header .task-colum-name .icon:hover{color:#72a114}.taskboard-table-header .task-colum-name .icon.hfold,.taskboard-table-header .task-colum-name .icon.hunfold{display:inline-block;-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.taskboard-table-header .task-colum-name.column-fold{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:.3rem 0}.taskboard-table-header .task-colum-name.column-fold span{display:none}.taskboard-table-header .task-colum-name.column-fold .hfold,.taskboard-table-header .task-colum-name.column-fold .hunfold{margin:0}.taskboard-table-body{height:700px;overflow-x:scroll;overflow-y:scroll;width:100%}.taskboard-table-body .task-column{-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;margin:0 10px 0 0;max-width:300px;width:300px}.taskboard-table-body .task-column:last-child{margin-right:0}.taskboard-table-body .column-fold .taskboard-task{max-width:40px;width:40px}.taskboard-table-body .task-row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:.5rem;min-height:10rem;width:100%}.taskboard-table-body .task-row:hover .new-task{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.taskboard-table-body .task-row.blocked .taskboard-userstory-box{background:rgba(255,0,0,.6);border-radius:3px}.taskboard-table-body .task-row.blocked .points-value,.taskboard-table-body .task-row.blocked a{color:rgba(255,255,255,.9);-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-table-body .task-row.blocked .points-value:hover,.taskboard-table-body .task-row.blocked a:hover{color:#fff;-webkit-transition:color .3s linear;transition:color .3s linear}.taskboard-table-body .task-row.blocked .taskboard-tasks-box{background:rgba(255,0,0,.1)}.taskboard-table-body .task-row.row-fold{min-height:0}.taskboard-table-body .task-row.row-fold .us-title{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.taskboard-table-body .task-row.row-fold .icon-bulk,.taskboard-table-body .task-row.row-fold .icon-plus,.taskboard-table-body .task-row.row-fold .points-value{display:none}.taskboard-table-body .taskboard-tasks-box{background:#f5f5f5}.taskboard-table-body .taskboard-userstory-box{padding:.5rem .5rem .5rem 1.5rem}.taskboard-table-body .taskboard-userstory-box .icon{color:#b8b8b8;position:absolute;right:.5rem;top:.7rem;-webkit-transition:color .2s linear;transition:color .2s linear}.taskboard-table-body .taskboard-userstory-box .icon:hover{color:#72a114}.taskboard-table-body .taskboard-userstory-box .icon.icon-plus{right:2rem}.taskboard-table-body .taskboard-userstory-box .icon.icon-vfold,.taskboard-table-body .taskboard-userstory-box .icon.icon-vunfold{left:0;right:inherit}.taskboard-table-body .avatar-task-link{display:none}.taskboard-table-body .avatar-assigned-to{display:block}.taskboard-userstory-box{position:relative}.taskboard-userstory-box .tag-list{display:none;margin-bottom:1rem}.taskboard-userstory-box .us-title{margin-bottom:0;margin-right:3rem}.taskboard-userstory-box .points-value{color:#b8b8b8}.taskboard-userstory-box .points-value span{margin-right:.1rem}.points-list a{color:#72a114;margin-left:.5rem}.points-list a:hover span{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.points-list span{opacity:0;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.login-form-container .forgot-pass{font-size:.8rem}.login-form-container .login-password{position:relative}.login-form-container input:focus+.forgot-pass{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.login-form-container .forgot-pass{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.login-form-container .forgot-pass:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.login-form-container .remember-me{vertical-align:top}.login-form-container .remember-me+label{cursor:pointer}.register-form-container .register-text{font-size:.8rem}.register-form-container{display:block}.register-form-container .register-text-top{display:block;margin-bottom:1rem;text-align:center}.forgot-form-container{text-align:center}.change-password-form-container .get-token{font-size:.8rem}.change-password-text{color:#444;text-align:center}.change-password-form-container .token-change-password{position:relative}.change-password-form-container input:focus+.get-token{opacity:0;-webkit-transition:opacity .5s linear;transition:opacity .5s linear}.change-password-form-container .get-token{color:#b8b8b8;opacity:1;position:absolute;right:1rem;top:.5rem;-webkit-transition:all .3s linear;transition:all .3s linear}.change-password-form-container .get-token:hover{color:#444;-webkit-transition:color .3s linear;transition:color .3s linear}.wiki-nav li{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.wiki-nav li.loading .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.wiki-nav li{border-bottom:1px solid #cdcdcd;text-transform:uppercase}.wiki-nav li:hover .icon{opacity:1;-webkit-transition:opacity 1s linear;transition:opacity 1s linear}.wiki-nav li a{display:block;padding:1rem 0 1rem 1rem}.wiki-nav li a span{cursor:pointer}.wiki-nav li .icon{color:#050505;float:right;opacity:0;-webkit-transition:opacity 1s linear;transition:opacity 1s linear}.wiki-nav li input{background:#444;color:#f5f5f5}.wiki-nav li input::-webkit-input-placeholder{color:#b8b8b8}.wiki-nav li input::-moz-placeholder{color:#b8b8b8}.wiki-nav li input:-moz-placeholder{color:#b8b8b8}.wiki-nav li input:-ms-input-placeholder{color:#b8b8b8}.wiki-nav li.loading{margin:0;padding:8px;text-align:center;width:100%}.wiki-nav li.loading .loading-spinner{max-height:1rem;max-width:1rem}.wiki-nav .button{color:#fff;display:block;margin-bottom:.5rem;text-align:center}.wiki-summary .username-edition .username{font-size:1.2rem}.wiki-summary:after{clear:both;content:'';display:table}.wiki-summary figure{float:left;margin-right:.5rem;vertical-align:sub;width:32px}.wiki-summary ul{-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.wiki-summary .username-edition{min-width:240px}.wiki-summary .username-edition span{display:block;float:none}.wiki-summary .username-edition .username{color:#9dce0a;white-space:nowrap}.wiki-summary .button{color:#fff;float:right}.admin-menu li{font-size:1.6rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;border-bottom:1px solid #b8b8b8;text-transform:uppercase}.admin-menu li:last-child{border-bottom:0}.admin-menu a{display:block;padding:1rem 0 1rem 1rem}.admin-menu .active .icon,.admin-menu a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-menu .icon{color:#050505;float:right;opacity:0}.admin-common .total{font-size:1.2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-common header h1{margin-bottom:0}.admin-common .admin-subtitle{color:#b8b8b8;margin:0}.admin-common .total{background-color:#f5f5f5;color:#444;padding:1rem}.admin-common .total:hover .edit-value{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu li{font-size:1.6rem}.admin-submenu h1{font-size:2rem}.admin-submenu li{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-submenu h1{color:#fff}.admin-submenu li{border-bottom:1px solid #a6b2a7;text-transform:uppercase}.admin-submenu li:last-child{border-bottom:0}.admin-submenu a{color:#fff;display:block;padding:1rem 0 1rem 1rem}.admin-submenu a.active,.admin-submenu a:hover{color:#050505}.admin-submenu a.active .icon,.admin-submenu a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu .icon{color:#fff;float:right;opacity:0}.admin-submenu .button-gray{padding:.5rem 0;text-align:center}.admin-submenu .button-gray:hover{background-color:#617463}.admin-submenu-roles li{font-size:1.6rem}.admin-submenu-roles h1{font-size:2rem}.admin-submenu-roles li{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-submenu-roles h1{color:#fff}.admin-submenu-roles li{border-bottom:1px solid #a6b2a7;text-transform:uppercase}.admin-submenu-roles li:last-child{border-bottom:0}.admin-submenu-roles a{color:#fff;display:block;padding:1rem 0 1rem 1rem}.admin-submenu-roles a.active,.admin-submenu-roles a:hover{color:#050505}.admin-submenu-roles a.active .icon,.admin-submenu-roles a:hover .icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-submenu-roles .icon{color:#fff;float:right;opacity:0}.admin-submenu-roles .button-gray{padding:.5rem 0;text-align:center}.admin-submenu-roles .button-gray:hover{background-color:#617463}.admin-roles .check input~.check-text{font-size:.8rem}.admin-roles .edit-value{font-size:1rem}.admin-roles .role-name{font-size:2rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif;color:#444}.admin-roles .edit-value{color:#b8b8b8;cursor:pointer;margin-left:.5rem;opacity:0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-roles .edit-role{-webkit-box-align:left;-webkit-align-items:left;-ms-flex-align:left;align-items:left;background-color:#f5f5f5;display:none;margin-bottom:1rem;padding:.5rem}.admin-roles .edit-role input{background-color:#fff;width:50%}.admin-roles .edit-role .icon-floppy{color:#b8b8b8;margin-left:.5rem;-webkit-transition:color .3s linear;transition:color .3s linear}.admin-roles .edit-role .icon-floppy:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.admin-roles .any-computable-role{background:red;color:#fff;margin-bottom:.5rem;padding:.5rem}.admin-roles .general-category{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;padding-bottom:2rem}.admin-roles .general-category .check{margin-left:.5rem}.admin-roles .check{background-color:#dcdcdc;border-radius:2px;cursor:pointer;height:1.5rem;overflow:hidden;position:relative;width:65px}.admin-roles .check input{cursor:pointer;height:500px;left:-10px;opacity:0;position:absolute;top:-10px;width:500px;z-index:999}.admin-roles .check input+div{background-color:#585858;height:25px;-webkit-transition:all .2s linear;transition:all .2s linear;width:50%}.admin-roles .check input~.check-text{color:#fff;position:absolute;top:.1rem}.admin-roles .check input~.check-yes{opacity:0;right:.5rem}.admin-roles .check input~.check-no{left:.5rem;opacity:.6}.admin-roles .check input:checked+div{background-color:#74a218;margin-left:50%;-webkit-transition:all .2s linear;transition:all .2s linear}.admin-roles .check input:checked~.check-yes{opacity:.6;right:.4rem}.admin-roles .check input:checked~.check-no{left:.4rem;opacity:0}.admin-functionalities .functionality .icon{font-size:3rem}.admin-functionalities .functionality span{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-functionalities form{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.admin-functionalities .functionality{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background-color:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin-bottom:.3rem;margin-right:.3rem;opacity:.5;padding:1rem;position:relative;-webkit-transition:all .2s linear;transition:all .2s linear;vertical-align:top;width:32%}.admin-functionalities .functionality.active{background-color:#e9f0da;opacity:1}.admin-functionalities .functionality .icon{-webkit-flex-basis:60px;-ms-flex-preferred-size:60px;flex-basis:60px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin:0 auto;min-height:60px}.admin-functionalities .functionality .desc{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:center}.admin-functionalities .functionality .activate-input{display:none}.admin-functionalities .functionality .activate-input+label{color:#fff;cursor:pointer;display:block;text-align:center}.admin-functionalities .functionality span{display:block}.admin-functionalities .functionality select{margin-top:1rem}.admin-functionalities .videoconference-attributes select{margin-bottom:.5rem}.admin-functionalities .button-green{color:#fff;display:block;text-align:center}.admin-project-export-result h3{font-size:1.2rem;font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-project-export-result .spin img{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;max-height:1rem;max-width:1rem;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32}.admin-project-export-buttons{margin-top:2rem}.admin-project-export-result{margin-top:1rem}.admin-project-export-result .spin{margin:0 auto;width:2.5rem}.admin-project-export-result .spin img{width:100%}.admin-project-export-result h3{background:#f5f5f5;color:#555;margin:.5rem;padding:.5rem;text-align:center}.admin-project-export-result p{color:#b8b8b8;margin:.5rem 0;text-align:center}.admin-membership-table .check input~.check-text,.admin-membership-table .row-admin label{font-size:.8rem}.admin-membership-table .delete{font-size:1.2rem}.admin-membership-table .avatar .name,.admin-membership-table .title{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-membership-table .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start}.admin-membership-table .avatar figcaption{margin-left:1rem;width:75%}.admin-membership-table .avatar figcaption span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.admin-membership-table .avatar img{-webkit-flex-basis:35px;-ms-flex-preferred-size:35px;flex-basis:35px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:35px}.admin-membership-table .avatar .email,.admin-membership-table .avatar .name{display:block;width:100%}.admin-membership-table .avatar .email{color:#b8b8b8}.admin-membership-table .header-role,.admin-membership-table .header-status{padding-left:.5rem}.admin-membership-table .row-role{padding-right:1rem}.admin-membership-table .row-status{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.admin-membership-table .active,.admin-membership-table .pending{padding:8px}.admin-membership-table .active{background-color:#f5f5f5}.admin-membership-table .pending{background-color:#ff8282;color:#fff}.admin-membership-table .pending .icon{float:rsdsdfdvsdvight}.admin-membership-table .pending:hover{background-color:red;color:#fff;-webkit-transition:background-color .3s linear;transition:background-color .3s linear}.admin-membership-table .delete{color:#b8b8b8}.admin-membership-table .delete:hover{color:red}.admin-membership-table .row-admin input{vertical-align:middle}.admin-membership-table .header-member,.admin-membership-table .header-role,.admin-membership-table .row-member,.admin-membership-table .row-role{-webkit-flex-basis:210px;-ms-flex-preferred-size:210px;flex-basis:210px;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3;min-width:210px}.admin-membership-table .header-admin,.admin-membership-table .row-admin{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;min-width:70px}.admin-membership-table .header-status,.admin-membership-table .row-status{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.admin-membership-table .check{background-color:#dcdcdc;border-radius:2px;cursor:pointer;height:1.5rem;overflow:hidden;position:relative;width:65px}.admin-membership-table .check input{cursor:pointer;height:500px;left:-10px;opacity:0;position:absolute;top:-10px;width:500px;z-index:999}.admin-membership-table .check input+div{background-color:#585858;height:25px;-webkit-transition:all .2s linear;transition:all .2s linear;width:50%}.admin-membership-table .check input~.check-text{color:#fff;position:absolute;top:.1rem}.admin-membership-table .check input~.check-yes{opacity:0;right:.5rem}.admin-membership-table .check input~.check-no{left:.5rem;opacity:.6}.admin-membership-table .check input:checked+div{background-color:#74a218;margin-left:50%;-webkit-transition:all .2s linear;transition:all .2s linear}.admin-membership-table .check input:checked~.check-yes{opacity:.6;right:.4rem}.admin-membership-table .check input:checked~.check-no{left:.4rem;opacity:0}.project-details .delete-project{font-size:.8rem}.project-details .privacy-settings label,.project-details input,.project-details label,.project-details textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.project-details form{max-width:700px;width:100%}.project-details fieldset{margin-bottom:1rem}.project-details label{display:block;margin-bottom:.2rem}.project-details textarea{height:10rem}.project-details .privacy-settings{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:2rem}.project-details .privacy-settings div{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-details .privacy-settings div:first-child{margin-right:.5rem}.project-details .privacy-settings label{background:#fff;border:1px solid #f5f5f5;cursor:pointer;display:block;text-align:center}.project-details .privacy-settings input:checked+label{background:#9dce0a;color:#fff}.project-details .button-green{color:#fff;display:block;text-align:center}.project-details .delete-project{display:block;margin-top:1rem}.default-values fieldset{margin-bottom:1rem}.default-values fieldset:last-child{margin-top:1.5rem}.default-values label,.default-values select{display:inline-block;width:49.7%}.default-values a{color:#fff;display:block;text-align:center}.project-values-row .icon,.project-values-settings a{font-size:1.2rem}.project-values-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.project-values-row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:1rem}.project-values-row div{margin-left:1rem;position:relative}.project-values-row .icon{color:#b8b8b8;opacity:0}.project-values-row .icon:hover{color:#444;-webkit-transition:all .2s ease-in;transition:all .2s ease-in}.project-values-header{border-bottom:2px solid #b8b8b8}.project-values-body .project-values-row:hover{background:#f6fceb;cursor:move;-webkit-transition:background .2s ease-in;transition:background .2s ease-in}.project-values-body .project-values-row:hover .icon{opacity:1;-webkit-transition:opacity .2s ease-in;transition:opacity .2s ease-in}.project-values-name{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.project-values-value{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.project-values-value .checksley-error-list{left:0;right:auto;top:35px;white-space:nowrap}.project-values-isclosed,.project-values-settings{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;text-align:right}.project-values-settings a{color:#555;margin-right:.5rem}.project-values-settings a:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.project-values-settings a:hover .icon-delete{color:red}.admin-third-parties .help .alt-image,.admin-third-parties .help code,.admin-third-parties .select-input-text .help-copy{font-size:.8rem}.admin-third-parties input,.admin-third-parties label,.admin-third-parties textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-third-parties form{margin:1rem 0;max-width:700px;width:100%}.admin-third-parties fieldset{margin-bottom:1rem}.admin-third-parties label{display:block;margin-bottom:.2rem}.admin-third-parties textarea{height:10rem}.admin-third-parties .submit-button{color:#fff;display:block;text-align:center}.admin-third-parties .select-input-text .field-with-option{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.admin-third-parties .select-input-text .option-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border:1px solid #b8b8b8;border-left:0;border-radius:0 5px 5px 0;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0 1rem}.admin-third-parties .select-input-text .help-copy{opacity:0}.admin-third-parties .select-input-text .help-copy.visible{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.admin-third-parties .help{margin-top:2rem}.admin-third-parties .help h3{font-family:opensans-semibold;margin-bottom:1rem}.admin-third-parties .help ol{padding:0 0 0 2rem}.admin-third-parties .help ol span{font-family:opensans-semibold}.admin-third-parties .help .img{margin-bottom:1rem}.admin-third-parties .help .alt-image{font-style:italic}.admin-third-parties .help code{background:#f5f5f5;direction:ltr;display:block;font-family:'courier new',monospace;line-height:1.4rem;margin-bottom:1rem;padding:.5rem;unicode-bidi:embed;white-space:pre;width:100%}.admin-third-parties .help .code-info{padding-left:1rem}.admin-third-parties .help .code-info li{margin-bottom:.5rem}.admin-third-parties .help .code-info span{font-family:opensans-semibold}.admin-webhooks .history-single-request-body span,.admin-webhooks .history-single-request-header a,.admin-webhooks .history-single-response-body span,.admin-webhooks .history-single-response-header a{font-size:.8rem}.admin-webhooks .history-single-request-header span:first-child,.admin-webhooks .history-single-response-header span:first-child,.admin-webhooks .table-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.admin-webhooks .history-single-request-body .response-container,.admin-webhooks .history-single-request-body textarea,.admin-webhooks .history-single-response-body .response-container,.admin-webhooks .history-single-response-body textarea{font-family:'courier new',monospace}.admin-webhooks .webhooks-table .row{border-bottom:0;padding:.5rem 0}.admin-webhooks .webhooks-table .row:hover .webhook-options-wrapper{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.admin-webhooks .table-header{border-bottom:1px solid #b8b8b8}.admin-webhooks .table-body .webhook-service{color:#555}.admin-webhooks .single-webhook-wrapper{border-bottom:1px solid #f5f5f5}.admin-webhooks .webhooks-options{margin-bottom:1rem;text-align:right}.admin-webhooks .webhook-service,.admin-webhooks .webhook-url{margin-right:.5rem}.admin-webhooks .webhook-service{-webkit-flex-basis:20%;-ms-flex-preferred-size:20%;flex-basis:20%;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0}.admin-webhooks .webhook-url{-webkit-flex-basis:400px;-ms-flex-preferred-size:400px;flex-basis:400px;-webkit-box-flex:8;-webkit-flex-grow:8;-ms-flex-positive:8;flex-grow:8}.admin-webhooks .webhook-url span{max-width:65%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#b8b8b8;display:inline-block;vertical-align:middle}.admin-webhooks .webhook-url a{color:#72a114;margin-left:.5rem}.admin-webhooks .webhook-url a:hover{color:#9dce0a}.admin-webhooks .webhook-options{-webkit-flex-basis:100px;-ms-flex-preferred-size:100px;flex-basis:100px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;min-width:100px;text-align:center}.admin-webhooks .webhook-options a{color:#b8b8b8;margin-right:.5rem;-webkit-transition:color .2s linear;transition:color .2s linear;vertical-align:middle}.admin-webhooks .webhook-options a:hover{color:#72a114;-webkit-transition:color .2s linear;transition:color .2s linear}.admin-webhooks .webhook-options-wrapper{opacity:0;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.admin-webhooks .webhook-url-inputs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.admin-webhooks .webhook-url-inputs fieldset{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:.3rem}.admin-webhooks .webhooks-history{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow:hidden}.admin-webhooks .webhooks-history.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:1000px}.admin-webhooks .history-single-wrapper{border-bottom:1px solid #f5f5f5;margin-left:22%}.admin-webhooks .history-single{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem;-webkit-transition:background .2s linear;transition:background .2s linear}.admin-webhooks .history-single:hover{background:rgba(157,206,10,.1);-webkit-transition:background .2s linear;transition:background .2s linear}.admin-webhooks .history-single.history-single-open:hover{background:0 0}.admin-webhooks .history-single.history-single-open .icon-arrow-bottom{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);-webkit-transition:-webkit-transform .3s linear;transition:transform .3s linear}.admin-webhooks .history-single .icon-arrow-bottom{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s linear;transition:transform .3s linear}.admin-webhooks .history-response-icon{background:#555;border-radius:25%;display:inline-block;height:.8rem;margin-right:.5rem;width:.8rem}.admin-webhooks .history-response-icon.history-success{background:#9dce0a}.admin-webhooks .history-response-icon.history-error{background:red}.admin-webhooks .history-single-response{max-height:0;-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;overflow:hidden}.admin-webhooks .history-single-response.open{-webkit-transition:max-height .5s ease-in;transition:max-height .5s ease-in;max-height:1000px}.admin-webhooks .history-single-request-header,.admin-webhooks .history-single-response-header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:1.5rem 0 .5rem}.admin-webhooks .history-single-request-header a,.admin-webhooks .history-single-request-header span:first-child,.admin-webhooks .history-single-response-header a,.admin-webhooks .history-single-response-header span:first-child{color:#b8b8b8}.admin-webhooks .history-single-request-header a:hover,.admin-webhooks .history-single-response-header a:hover{color:#9dce0a;-webkit-transition:color .2s linear;transition:color .2s linear}.admin-webhooks .history-single-request-header .icon,.admin-webhooks .history-single-response-header .icon{margin-right:.3rem;vertical-align:middle}.admin-webhooks .history-single-request-body .response-container,.admin-webhooks .history-single-response-body .response-container{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:#f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-justify-content:space-around;-ms-flex-pack:distribute;justify-content:space-around;margin-bottom:.5rem}.admin-webhooks .history-single-request-body span,.admin-webhooks .history-single-response-body span{color:#b8b8b8;-webkit-flex-basis:20%;-ms-flex-preferred-size:20%;flex-basis:20%;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;text-align:center}.admin-webhooks .history-single-request-body textarea,.admin-webhooks .history-single-response-body textarea{border:0;-webkit-box-flex:2;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2;min-height:7.5rem}.admin-webhooks .history-single-response-body textarea{min-height:10rem}.admin-contrib .help .alt-image,.admin-contrib .help code,.admin-contrib .select-input-text .help-copy{font-size:.8rem}.admin-contrib input[type=text],.admin-contrib label,.admin-contrib textarea{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.admin-contrib form{margin:1rem 0;max-width:700px;width:100%}.admin-contrib fieldset{margin-bottom:1rem}.admin-contrib label{display:block;margin-bottom:.2rem}.admin-contrib textarea{height:10rem}.admin-contrib .button-green{color:#fff;display:block;text-align:center}.admin-contrib .select-input-text .field-with-option{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.admin-contrib .select-input-text .option-wrapper{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border:1px solid #b8b8b8;border-left:0;border-radius:0 5px 5px 0;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0 1rem}.admin-contrib .select-input-text .help-copy{opacity:0}.admin-contrib .select-input-text .help-copy.visible{opacity:1;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.admin-contrib .help{margin-top:2rem}.admin-contrib .help h3{font-family:opensans-semibold;margin-bottom:1rem}.admin-contrib .help ol{padding:0 0 0 2rem}.admin-contrib .help ol span{font-family:opensans-semibold}.admin-contrib .help .img{margin-bottom:1rem}.admin-contrib .help .alt-image{font-style:italic}.admin-contrib .help code{background:#f5f5f5;direction:ltr;display:block;font-family:'courier new',monospace;line-height:1.4rem;margin-bottom:1rem;padding:.5rem;unicode-bidi:embed;white-space:pre;width:100%}.admin-contrib .help .code-info{padding-left:1rem}.admin-contrib .help .code-info li{margin-bottom:.5rem}.admin-contrib .help .code-info span{font-family:opensans-semibold}.user-profile form .avatar-container p{font-size:.5rem}.user-profile .delete-account,.user-profile form .avatar-container .use-gravatar{font-size:.8rem}.user-profile label{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user-profile form .avatar-container span{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.user-profile form .avatar-container .loading-spinner{-webkit-animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;animation:rotate 1.5s cubic-bezier(0,.05,.87,1.04) infinite alternate;margin:0 auto;max-height:1rem;max-width:1rem}.user-profile form{max-width:700px;width:100%}.user-profile form .container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.user-profile form .avatar-container{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;margin-right:1rem}.user-profile form .avatar-container .image-container{position:relative}.user-profile form .avatar-container .avatar{border-radius:8%;width:100%}.user-profile form .avatar-container .overlay{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;background:rgba(5,5,5,.9);bottom:0;display:none;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;left:0;position:absolute;right:0;top:0;width:100%}.user-profile form .avatar-container .loading-spinner{border:0;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-transform-origin:32 32;-ms-transform-origin:32 32;transform-origin:32 32;width:30%}.user-profile form .avatar-container p{line-height:.8rem;margin-bottom:.3rem;text-align:center}.user-profile form .avatar-container .use-gravatar{cursor:pointer;display:inline-block;text-align:center;width:100%}.user-profile form .data{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.user-profile fieldset{margin-bottom:1rem}.user-profile .submit{margin-top:2rem}.user-profile label{display:block;margin-bottom:.5rem}.user-profile .button-green{color:#fff;cursor:pointer;display:block;padding:12px;text-align:center}.user-profile .delete-account{display:block;margin-top:1rem}.user-change-password label{font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.user-change-password fieldset{margin-bottom:1rem;width:50%}.user-change-password fieldset:last-child{margin-top:2rem}.user-change-password label{display:block;margin-bottom:.5rem}.user-change-password .button-green{color:#fff;display:block;padding:12px;text-align:center}.policy-table .policy-table-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.policy-table .policy-table-row{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #f5f5f5;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.policy-table .policy-table-header{border-bottom:2px solid #b8b8b8}.policy-table .policy-table-all,.policy-table .policy-table-involved,.policy-table .policy-table-none,.policy-table .policy-table-project{padding:1rem}.policy-table .policy-table-project{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:3;-webkit-flex-grow:3;-ms-flex-positive:3;flex-grow:3}.policy-table .policy-table-all,.policy-table .policy-table-involved,.policy-table .policy-table-none{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.policy-table input{display:none}.policy-table input:checked+label{background:#72a114;-webkit-transition:background .3s linear;transition:background .3s linear}.policy-table label{background:#b8b8b8;border-radius:5px;color:#fff;display:block;padding:.5rem}.policy-table label:hover{background:#9dce0a;cursor:pointer;-webkit-transition:background .3s linear;transition:background .3s linear}.team-filters nav li{font-size:1.6rem;font-family:OpenSans-CondLight,Arial,Helvetica,sans-serif}.team-filters .search-in{margin-bottom:1rem;position:relative}.team-filters nav li{border-bottom:1px solid #b8b8b8;text-transform:uppercase}.team-filters nav li:last-child{border-bottom:0}.team-filters nav a{display:block;padding:1rem 0 1rem 1rem}.team-filters nav a.active,.team-filters nav a:hover{color:#72a114;-webkit-transition:color .3s linear;transition:color .3s linear}.team-filters nav .active,.team-filters nav a.active.icon{opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.team-filters nav .icon{color:#050505;float:right;opacity:0}.table-team .leave-project,.table-team .popover,.table-team .popover a{font-size:.8rem}.table-team .attribute .icon,.table-team .attribute .points{font-size:2rem}.table-team .popover{font-family:opensans-regular,Arial,Helvetica,sans-serif;line-height:1.3rem}.table-team .attribute .points,.table-team .avatar .name,.table-team .team-header{font-family:opensans-semibold,Arial,Helvetica,sans-serif}.table-team .row{padding:.5rem}.table-team .username{-webkit-box-flex:3;-webkit-flex:3;-ms-flex:3;flex:3;min-width:300px}.table-team .member-stats{-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:6;-webkit-flex:6;-ms-flex:6;flex:6;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.table-team .attribute{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;position:relative;text-align:center}.table-team .attribute .icon,.table-team .attribute .points{color:#444}.table-team .attribute .icon.top,.table-team .attribute .points.top{color:#9dce0a}.table-team .attribute .top{color:#9dce0a;opacity:1}.table-team .attribute:hover .popover{display:block}.table-team .leave-project{color:#b8b8b8;display:block}.table-team .leave-project .icon{margin-right:.2rem}.table-team .leave-project:hover .icon{color:red;-webkit-transition:color .3s linear;transition:color .3s linear}.table-team .team-header{border-bottom:0}.table-team .hero{width:100%}.table-team .hero .row{background:#fcfcfc;border-bottom:0;margin:1rem 0}.table-team .avatar{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.table-team .avatar img{-webkit-flex-basis:66px;-ms-flex-preferred-size:66px;flex-basis:66px;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:66px}.table-team .avatar figcaption{margin-left:1rem;width:65%}.table-team .avatar figcaption span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}.table-team .avatar .name,.table-team .avatar .position{display:block;width:100%}.table-team .avatar .position{color:#b8b8b8}.table-team .popover{background:#050505;bottom:30px;color:#fff;display:none;left:0;list-style-type:none;margin:0;padding:10px;position:absolute;width:100%;z-index:99}.table-team .popover a{border-bottom:1px solid #444;color:#fff;display:block;padding:10px 2px}.table-team .popover a:last-child{border:0}.table-team .popover a:hover{color:#9dce0a;-webkit-transition:color .3s linear;transition:color .3s linear}.table-team .popover:after{background:#050505;bottom:-5px;content:'';height:15px;left:50%;position:absolute;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:15px}.lightbox-generic-notion section{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-basis:600px;-ms-flex-preferred-size:600px;flex-basis:600px}.kanban-table-header,.taskboard-table-header{height:40px} \ No newline at end of file diff --git a/dist/svg/spinner-circle.svg b/dist/svg/spinner-circle.svg new file mode 100644 index 0000000..27cdb3b --- /dev/null +++ b/dist/svg/spinner-circle.svg @@ -0,0 +1 @@ + \ No newline at end of file