diff --git a/dist/index.html b/dist/index.html index 7e23a47..d2d1d84 100644 --- a/dist/index.html +++ b/dist/index.html @@ -157,8 +157,8 @@

Loading...

- - - + + + \ No newline at end of file diff --git a/dist/js/app-loader.js b/dist/js/app-loader.js index eb61672..6990f71 100644 --- a/dist/js/app-loader.js +++ b/dist/js/app-loader.js @@ -1,7 +1,7 @@ (function() { var promise, version; - version = 1422342785556; + version = 1422345545099; window.taigaConfig = { "api": "http://localhost:8000/api/v1/", diff --git a/dist/js/app.js b/dist/js/app.js index 997087c..5e4b46c 100644 --- a/dist/js/app.js +++ b/dist/js/app.js @@ -5,7 +5,7 @@ return template=$template.get("common/components/editable-description.html"),noD },{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,templateUrl:"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; +}),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,maxColumnWidth;return avatarWidth=40,maxColumnWidth=300,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",maxColumnWidth)}}(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,templateUrl:"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() diff --git a/dist/js/app.js.map b/dist/js/app.js.map index 0e980b6..4aeee2d 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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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 templateUrl: \"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 +{"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;AACA;AC1/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, maxColumnWidth;\n avatarWidth = 40;\n maxColumnWidth = 300;\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\", maxColumnWidth);\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 templateUrl: \"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 index c1639c9..61d7b9e 100644 --- a/dist/js/templates.js +++ b/dist/js/templates.js @@ -87,6 +87,10 @@ $templateCache.put("wiki/editable-wiki-content.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/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/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 %>
"); @@ -101,10 +105,6 @@ $templateCache.put("common/components/main-title.html","%\" 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
"); diff --git a/dist/styles/main.css b/dist/styles/main.css index da0fd5a..0c4e8bd 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 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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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{padding:0 .5rem 0 .8rem}.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{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-wrapper{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:55px}.kanban-task-minimized .avatar-wrapper img{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:135px}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-status a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-role a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-points a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-points-open a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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: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{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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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{padding:0 .5rem 0 .8rem}.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{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-wrapper{-webkit-flex-basis:50px;-ms-flex-preferred-size:50px;flex-basis:50px;-webkit-box-flex:0;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;width:55px}.kanban-task-minimized .avatar-wrapper img{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:135px}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-status a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-role a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-points a:hover.point{color:#fff}.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 a:hover.point,.backlog-table-header .pop-points-open a:hover.point{color:#fff}.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 a:hover.point{color:#fff}.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