PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB` sh-3ll

HOME


sh-3ll 1.0
DIR:/usr/local/jetapps/var/www/jetbackup5/docroot/app/
Upload File :
Current File : //usr/local/jetapps/var/www/jetbackup5/docroot/app/main.min.js
(function () {
'use strict';

define('app',[
], function () {

	var app = angular.module("JetBackupApp", [
		"ngRoute",
		"ngAnimate",
		"ngSanitize",
		"ngMaterial",
		"ui.bootstrap",
		"permission",
		"permission.ng",
		"angular-loading-bar",
		"moment-picker",
		"chart.js",
		"jm.i18next"
	]).run(["permissions", function(permissions) {
		permissions.init(window.PAGE.permissions);
	}]).config([
		'$routeProvider', '$httpProvider', '$animateProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$permissionProvider', '$provide', 'cfpLoadingBarProvider',
		function ($routeProvider, $httpProvider, $animateProvider, $controllerProvider, $compileProvider, $filterProvider, $permissionProvider, $provide, cfpLoadingBarProvider) {

			$animateProvider.classNameFilter(/(action-module)/);
			$permissionProvider.suppressUndefinedPermissionWarning(true);

			cfpLoadingBarProvider.includeSpinner = false;
			cfpLoadingBarProvider.includeBar = true;
			cfpLoadingBarProvider.parentSelector = '#loading-bar-container';

			$httpProvider.interceptors.push('responseObserver');
			$httpProvider.defaults.ignoreLoadingBar = true;

			app.register = {
				controller: $controllerProvider.register,
				directive: $compileProvider.directive,
				filter: $filterProvider.register,
				factory: $provide.factory,
				service: $provide.service
			};

			var template = window.PAGE.template;
			var path = window.PAGE.path.media + '/app/views';
			var version = window.PAGE.info.version;
			var rootPermissions =  { permissions: { only: 'isRoot', redirectTo: '/' } };
			var allPermissions =  { permissions: {
					except: ['isLicenseIssue', 'isDisableUI' ,'isAgreement', 'isDisasterRecovery', 'isAgreementPanel'],
					redirectTo: {
						isLicenseIssue: '/license',
						isDisableUI: '/disableui',
						isAgreement: '/agreement',
						isDisasterRecovery: '/disasterRecovery',
						isAgreementPanel: '/agreementPanel',
					}
				}};

			if(template === 'reseller') {

				allPermissions.permissions.except.push('isShowcase');
				allPermissions.permissions.redirectTo.isShowcase = '/showcase';
				
				$routeProvider
				.when('/accounts',						{ templateUrl: path + "/accounts.htm?v=" + version, data: { permissions: { only: 'canManageAccounts', redirectTo: '/' } } })
				.when('/accountsOrphans',				{ templateUrl: path + "/accountsOrphans.htm?v=" + version, data: { permissions: { only: ['canManageAccounts','isReseller'], redirectTo: '/' } } })
				.when('/accountManage/:id',			{ templateUrl: path + "/accountManage.htm?v=" + version, data: { permissions: { only: 'canManageAccounts', redirectTo: '/' } } })
				.when('/alerts',						{ templateUrl: path + "/alerts.htm?v=" + version, data: { permissions: { only: 'canViewAlerts', redirectTo: '/' } } })
				.when('/queue',						{ templateUrl: path + "/queue.htm?v=" + version, data: { permissions: { only: 'canManageQueue', redirectTo: '/' } } })
				.when('/destinations',					{ templateUrl: path + "/destinations.htm?v=" + version, data: { permissions: { only: 'canManageDestinations', redirectTo: '/' } } })
				.when('/destinationManage/:id', 		{ templateUrl: path + "/destinationManage.htm?v=" + version, data: { permissions: { only: 'canManageDestinations', redirectTo: '/' } } })
				.when('/destinationManage', 			{ templateUrl: path + "/destinationManage.htm?v=" + version, data: { permissions: { only: 'canManageDestinations', redirectTo: '/' } } })
				.when("/restoreConditions", 			{ templateUrl: path + "/restoreConditions.htm?v=" + version, data: { permissions: { only: 'isRoot', redirectTo: '/' } } })
				.when("/restoreConditionManage", 		{ templateUrl: path + "/restoreConditionManage.htm?v=" + version, data: { permissions: { only: 'isRoot', redirectTo: '/' } } })
				.when("/restoreConditionManage/:id", 	{ templateUrl: path + "/restoreConditionManage.htm?v=" + version, data: { permissions: { only: 'isRoot', redirectTo: '/' } } })
				.when("/filePermissions", 				{ templateUrl: path + "/filePermissions.htm?v=" + version, data: rootPermissions })
				.when("/filePermissionsManage", 		{ templateUrl: path + "/filePermissionsManage.htm?v=" + version, data: rootPermissions })
				.when("/filePermissionsManage/:id", 	{ templateUrl: path + "/filePermissionsManage.htm?v=" + version, data: rootPermissions })
				.when("/queuePriorities", 				{ templateUrl: path + "/queuePriorities.htm?v=" + version, data: rootPermissions })
				.when("/queuePriorityManage", 			{ templateUrl: path + "/queuePriorityManage.htm?v=" + version, data: rootPermissions })
				.when("/queuePriorityManage/:id", 		{ templateUrl: path + "/queuePriorityManage.htm?v=" + version, data: rootPermissions })
				.when('/permissions',					{ templateUrl: path + "/permissions.htm?v=" + version, data: { permissions: { only: 'canManagePermissions', redirectTo: '/' } } })
				.when('/backupJobs',					{ templateUrl: path + "/backupJobs.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				.when("/backupJobManage/:id",			{ templateUrl: path + "/backupJobManage.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				.when("/backupJobManage",				{ templateUrl: path + "/backupJobManage.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				.when('/cloneJobs',					{ templateUrl: path + "/cloneJobs.htm?v=" + version, data: { permissions: { only: 'canManageCloneJobs', redirectTo: '/' } } })
				.when("/cloneJobManage/:id",			{ templateUrl: path + "/cloneJobManage.htm?v=" + version, data: { permissions: { only: 'canManageCloneJobs', redirectTo: '/' } } })
				.when("/cloneJobManage",				{ templateUrl: path + "/cloneJobManage.htm?v=" + version, data: { permissions: { only: 'canManageCloneJobs', redirectTo: '/' } } })
				.when('/settings', 					{ templateUrl: path + "/settings.htm?v=" + version, data: rootPermissions })
				.when('/settings/:section', 			{ templateUrl: path + "/settings.htm?v=" + version, data: rootPermissions })
				.when('/settings/notification/manage', { templateUrl: path + "/settings/notificationManage.htm?v=" + version, data: rootPermissions })
				.when('/settings/notification/manage/:id', { templateUrl: path + "/settings/notificationManage.htm?v=" + version, data: rootPermissions })
				.when('/security',						{ templateUrl: path + "/security.htm?v=" + version, data: rootPermissions })
				.when('/extension',						{ templateUrl: path + "/extension.htm?v=" + version, data: { permissions: { only: 'isWPIntegration', redirectTo: '/' } } })
				.when('/downloads',					{ templateUrl: path + "/downloads.htm?v=" + version, data: { permissions: { only: 'canDownloadBackups', redirectTo: '/' } } })
				.when('/restore/singleaccount',						{
					templateUrl: path + "/restore.htm?v=" + version,
					controller: 'accountBackups',
					resolve: {
						$uibModalInstance: function () { return {close:function(){}}; },
						account: function() { return null; }
					},
					data: { permissions: { only: 'canManageAccountBackups', redirectTo: '/' } } })
				.when('/restore/:section',						{ templateUrl: path + "/restore.htm?v=" + version, data: { permissions: { only: 'canManageAccountBackups', redirectTo: '/' } } })
				//.when('/restoreSingle',				{ templateUrl: path + "/restoreSingle.htm?v=" + version, controller: "accountBackups", resolve: { $uibModalInstance: function () { return {close:function(){}}; }, account: function() { return window.PAGE.account; } }, data: { permissions: { only: 'canManageAccountBackups', redirectTo: '/' } } })
				.when('/hooks',						{ templateUrl: path + "/hooks.htm?v=" + version, data: { permissions: { only: 'canManageHooks', redirectTo: '/' } } })
				.when("/hookManage",					{ templateUrl: path + "/hookManage.htm?v=" + version, data: { permissions: { only: 'canManageHooks', redirectTo: '/' } } })
				.when("/hookManage/:id",				{ templateUrl: path + "/hookManage.htm?v=" + version, data: { permissions: { only: 'canManageHooks', redirectTo: '/' } } })
				.when('/tags',							{ templateUrl: path + "/tags.htm?v=" + version, data: rootPermissions })
				.when("/tagManage",					{ templateUrl: path + "/tagManage.htm?v=" + version, data: rootPermissions })
				.when("/tagManage/:id",				{ templateUrl: path + "/tagManage.htm?v=" + version, data: rootPermissions })
				.when('/plugins',						{ templateUrl: path + "/plugins.htm?v=" + version, data: rootPermissions })
				.when('/plugins/:section',				{ templateUrl: path + "/plugins.htm?v=" + version, data: rootPermissions })
				.when('/plugin/:plugin',				{ templateUrl: path + "/plugin.htm?v=" + version, data: allPermissions })
				.when('/repositoryManage', 			{ templateUrl: path + "/repositoryManage.htm?v=" + version, data: rootPermissions })
				.when('/repositoryManage/:id', 		{ templateUrl: path + "/repositoryManage.htm?v=" + version, data: rootPermissions })
				.when('/logs', 						{ templateUrl: path + "/logs.htm?v=" + version, data: { permissions: { only: 'canViewLogs', redirectTo: '/' } } })
				.when('/fileManager/:type/:id', 		{ templateUrl: path + "/fileManager.htm?v=" + version, data: { permissions: { only: ['canManageDestinations','canManageFileBackups'], redirectTo: '/' } } })
				//.when("/accountFilterGroups", 			{ templateUrl: path + "/accountFilterGroups.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				//.when("/accountFilterGroupManage", 		{ templateUrl: path + "/accountFilterGroupManage.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				//.when("/accountFilterGroupManage/:id", 	{ templateUrl: path + "/accountFilterGroupManage.htm?v=" + version, data: { permissions: { only: 'canManageBackupJobs', redirectTo: '/' } } })
				.when('/accountFilters',				{ templateUrl: path + "/accountFilters.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/accountFilterManage',			{ templateUrl: path + "/accountFilterManage.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/accountFilterManage/:id',		{ templateUrl: path + "/accountFilterManage.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/schedules',				{ templateUrl: path + "/schedules.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/scheduleManage',			{ templateUrl: path + "/scheduleManage.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/scheduleManage/:id',		{ templateUrl: path + "/scheduleManage.htm?v=" + version, data: { permissions: { only: ['canManageBackupJobs','canManageCloneJobs'], redirectTo: '/' } } })
				.when('/license', 						{ templateUrl: path + "/license.htm?v=" + version, 	data: { permissions: { only: 'isLicenseIssue', redirectTo: '/' } } })
				.when("/disasterRecovery", 			{ templateUrl: path + "/disasterRecovery.htm?v=" + version, data: { permissions: { only: 'isDisasterRecovery', except: ['isDisableUI', 'isLicenseIssue', 'isAgreement'], redirectTo: '/' } } })
				.when('/agreement', 					{ templateUrl: path + "/agreement.htm?v=" + version, data: { permissions: { only: 'isAgreement', except: ['isDisableUI', 'isLicenseIssue'], redirectTo: '/' } } })
				.when('/agreementPanel', 				{ templateUrl: path + "/agreementPanel.htm?v=" + version, data: { permissions: { only: 'isAgreementPanel', except: ['isDisableUI', 'isLicenseIssue', 'isAgreement','isDisasterRecovery'], redirectTo: '/' } } })
				.when('/disableui', 					{ templateUrl: path + "/disableUI.htm?v=" + version, data: { permissions: { only: 'isDisableUI', except: ['isLicenseIssue'], redirectTo: '/' } } })
				.when('/showcase', 					{ templateUrl: path + "/showcase.htm?v=" + version, data: { permissions: { only: 'isShowcase', except: ['isLicenseIssue', 'isAgreement', 'isAgreementPanel', 'isDisasterRecovery'], redirectTo: '/' } } })
				.when('/support', 						{ templateUrl: path + "/support.htm?v=" + version, data: rootPermissions })
				.when('/404', 							{ templateUrl: path + "/404.htm?v=" + version })
				.when('/myAccount',					{ templateUrl: path + "/myAccount.htm?v=" + version, data: allPermissions })
				.when('/', 							{ templateUrl: path + "/dashboard.htm?v=" + version, data: allPermissions })
				.otherwise('/404');
			} else {
				
				$routeProvider
				.when('/alerts',				{ templateUrl: path + "/alerts.htm?v=" + version, data: { permissions: { only: 'canViewAlerts', redirectTo: '/' } } })
				.when('/queue',				{ templateUrl: path + "/queue.htm?v=" + version, data: { permissions: { only: 'canManageQueue', redirectTo: '/' } } })
				.when('/downloads',			{ templateUrl: path + "/downloads.htm?v=" + version, data: { permissions: { only: 'canDownloadBackups', redirectTo: '/' } } })
				.when('/restore/:type',		{ templateUrl: path + "_enduser/restore.htm?v=" + version, data: { permissions: { only: 'canManageAccountBackups', redirectTo: '/' } } })
				.when('/disableui', 					{ templateUrl: path + "/disableUI.htm?v=" + version, data: { permissions: { only: 'isDisableUI', except: ['isLicenseIssue'], redirectTo: '/' } } })
				.when('/license', 						{ templateUrl: path + "_enduser/rootActionRequired.htm?v=" + version, 	data: { permissions: { only: 'isLicenseIssue', redirectTo: '/' } } })
				.when('/plugin/:plugin',				{ templateUrl: path + "/plugin.htm?v=" + version, data: allPermissions })
				.when('/disasterRecovery', 			{ templateUrl: path + "_enduser/rootActionRequired.htm?v=" + version, data: { permissions: { only: 'isDisasterRecovery', except: ['isDisableUI', 'isLicenseIssue', 'isAgreement'], redirectTo: '/' } } })
				.when('/agreement', 					{ templateUrl: path + "_enduser/rootActionRequired.htm?v=" + version, data: { permissions: { only: 'isAgreement', except: ['isDisableUI', 'isLicenseIssue'], redirectTo: '/' } } })
				.when('/agreementPanel', 				{ templateUrl: path + "/agreementPanel.htm?v=" + version, data: { permissions: { only: 'isAgreementPanel', except: ['isDisableUI', 'isLicenseIssue', 'isAgreement','isDisasterRecovery'], redirectTo: '/' } } })
				.when('/404', 						{ templateUrl: path + "/404.htm?v=" + version })
				.when('/myAccount',					{ templateUrl: path + "/myAccount.htm?v=" + version, data: allPermissions })
				.when('/', 							{ templateUrl: path + "_enduser/dashboard.htm?v=" + version, data: allPermissions })
				.otherwise('/404');
			}
		}
	]).controller("JetBackup",
		["$rootScope", "$scope", "$location", "$route", "$timeout", "lang", "permissions", "consts", "util", "api", "alert", "$uibModalStack",
			function($rootScope, $scope, $location, $route, $timeout, lang, permissions, consts, util, api, alert, $uibModalStack) {
			
				$rootScope.util = util;
				$rootScope.const = consts;
				$rootScope.perm = permissions;
				$rootScope.lang = lang;
				$rootScope.path = window.PAGE.path;
				$rootScope.template = window.PAGE.template;
				$rootScope.primaryURL = $rootScope.path.location + window.location.search + '#!';
				$rootScope.loggedAccount = window.PAGE.account;
				$rootScope.license = window.PAGE.license;
				$rootScope.plugins = window.PAGE.plugins;
				$rootScope.avx_enabled = window.PAGE.avxenabled;
				$rootScope.logoutURL = window.PAGE.logout_url !== undefined ? window.PAGE.logout_url : '';

				$rootScope.reloadPage = function () {
					window.location.reload();
				};
				
				app.registerPluginController = function(plugin, callback) {
					app.registerController(
						plugin.type + plugin.code,
						'plugins/' + plugin.type + '/' + plugin.code,
						callback
					);
				};

				app.registerShowcaseController = function(showcase, callback) {
					app.registerController(
						showcase.feature + showcase.order,
						'showcase/' + showcase.order + "_" + showcase.feature,
						callback
					);
				};

				app.registerController = function(controllerName, controllerPath, callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function() {};

					var controllerFile = controllerPath + '/controller';

					require.undef(controllerFile);
					require([controllerFile], function () {
						var queue = app._invokeQueue;
						for(var i = 0; i < queue.length; i++) {
							var controller = queue[i];
							var pattern = new RegExp("^" + controllerName + "($|_)");
							if(controller[0] !== '$controllerProvider' || controller[1] !== 'register' || !pattern.test(controller[2][0])) continue;
							app.register.controller(controller[2][0], controller[2][1]);
						}

						$timeout(callback($scope.path.media + '/app/' + controllerPath, controllerName));
					});
				};

				$rootScope.includePath = function(file, views) {
					if(!file) return '';
					if(!views) views = 'views';
					return $rootScope.path.media + '/app/' + views + '/' + file + '.htm?v=' + $rootScope.info.version;
				};

				$rootScope.downloadURL = function (args) {
					var sep = /\?/.test($scope.path.download) ? '&' : '?';
					return $scope.path.download + sep + args;
				};

				$rootScope.changeView = function(view) {
					$uibModalStack.dismissAll();
					$location.path(view);
				};

				$rootScope.info = window.PAGE.info;
				$rootScope.info.currentYear = new Date().getUTCFullYear();

				$rootScope.menuItem = 'Dashboard';
				$rootScope.$on('menuItem', function(event, item) { $rootScope.menuItem = item; });

				$rootScope.menuExpanded = !!parseInt(localStorage.getItem('menuExpanded'));
				$scope.toggleMenu = function() {
					$rootScope.menuExpanded = !$rootScope.menuExpanded;
					localStorage.setItem('menuExpanded', $scope.menuExpanded ? 1 : 0);
				};

				$rootScope.expandedRow = {};
				$rootScope.openActions = function(row, group) {
					if(group === undefined) group = 'general';
					$rootScope.expandedRow[group] = ($rootScope.expandedRow[group] !== undefined && $rootScope.expandedRow[group] === row) ? undefined : row;
				};

				$rootScope.isOpenedActions = function(row, group) {
					if(group === undefined) group = 'general';
					return $rootScope.expandedRow[group] === row;
				};

				$rootScope.$on('$routeChangeStart', function() { lang.initNS('dashboard'); });

				$rootScope.processStatus = true;
				$rootScope.processSyncAccountsStatus = true;
				$rootScope.inRescueMode = true;
				$rootScope.canDeleteSnapshots = false;

				$scope.checkProcess = function () {
					api.getProcessStatus({
						withLoader: false,
						success: function(data) {
							$rootScope.processStatus = !!data.status;
							$rootScope.processSyncAccountsStatus = !data.sync_accounts;
							$rootScope.inRescueMode = !!data.rescue;
							$rootScope.canDeleteSnapshots = !!data.delete_snapshots;

							// if service is up check every 30 sec, if down every 5 sec
							setTimeout($scope.checkProcess, $rootScope.processStatus && $rootScope.processSyncAccountsStatus ? 30000 : 2000);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.checkProcess();
			}
		]
	).factory('responseObserver', ["$q", "storage", function responseObserver($q, storage) {
		return {
			responseError: function(errorResponse) {

				var apiConfig = storage.create('api');

				// On valid response - reset the counter
				if(errorResponse.status < 300) {
					apiConfig.set('failedCounter', 0);
					apiConfig.save();
				}
				// On invalid response - count for 5 seconds and then reload the page
				else {
					var now = (new Date()).getTime();
					var failedCounter = apiConfig.get('failedCounter', 0);
					if(failedCounter == 0) failedCounter = now;

					if((now - failedCounter) >= 10000) {
						apiConfig.set('failedCounter', 0);
						apiConfig.save();
						location.reload();
					} else {
						apiConfig.set('failedCounter', failedCounter);
						apiConfig.save();
					}
				}

				return $q.reject(errorResponse);
			}
		};
	}]);

	return app;
});


define('controllers/404',['app'], function(app) {
	app.controller("404",
		["$rootScope", "$scope", "cfpLoadingBar",
			function ($rootScope, $scope, cfpLoadingBar) {
				cfpLoadingBar.complete();
			}
		]
	);
});


define('controllers/myAccount',['app'], function(app) {
	app.controller("myAccount",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "$q", "api", "meta", "lang", "filter", "util", "consts", "confirm", "alert",
			function ($rootScope, $scope, $location, $timeout, $interval, $q, api, meta, lang, filter, util, consts, confirm, alert) {
				$rootScope.$emit('menuItem', 'Accounts');


				$scope.info = {};
				$scope.details = {
					email: '',
					backup_type: 0,
					encryption_key: 0,
					privacy: 0
				};

				$scope.saveData = util.duplicateObject($scope.details);

				$scope.encryptionKey = '';
				$scope.currentEncryptionKey = '';
				$scope.saveing = false;
				$scope.changed = false;

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.requireEncryptionKey = function() {
					return ($scope.details.backup_type == 1 && $scope.details.encryption_key_type == 1 &&
						($scope.saveData.backup_type != 1 || $scope.saveData.encryption_key_type != 1));
				};

				$scope.resetEncryptionKey = function() {

					confirm.open({
						message: lang.t("Once you reset the account encryption key, ALL BACKUPS becomes inaccessible and will be deleted."),
						confirmLabel: lang.t("Delete Encryption Key"),
						confirm: function () {
							api.resetEncryptionKey({ 
								data: { _id: $scope.details._id }, 
								success: function (data, message) {
									$scope.details.secret_key = false;
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.saveChanges = function() {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);
					if($scope.currentEncryptionKey) apiParams.encryption_key = $scope.currentEncryptionKey;

					$scope.encryptionKey = '';
					$scope.currentEncryptionKey = '';

					api.manageMyAccount({ 
						data: apiParams,
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.details = util.duplicateObject($scope.saveData);
							if(data.encryption_key !== undefined) $scope.encryptionKey = data.encryption_key;
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				$scope.fetchAccountData = function() {

					api.getMyAccount({
						success: function(data) {
							$scope.info = data.info;
							delete data.info;
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});
				};

				$timeout(function () {
					$scope.fetchAccountData();
				});

			}
		]
	);
});


define('controllers/agreement',['app'], function(app) {
	app.controller("agreement",
		["$rootScope", "$scope", "$location", "api", "alert", "lang", "permissions",
			function ($rootScope, $scope, $location, api, alert, lang, permissions) {

				$scope.currYear = new Date().getYear() + 1900;

				$scope.setAgree = function () {

					api.approveAgreement({
						success: function() {
							window.PAGE.system.agreement = false;
							permissions.init(window.PAGE.permissions);
							$location.path('/');
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				}
			}
		]
	);
});


define('controllers/agreementPanel',['app'], function(app) {
	app.controller("agreementPanel",
		["$rootScope", "$scope", "$location", "api", "alert", "lang", "permissions",
			function ($rootScope, $scope, $location, api, alert, lang, permissions) {

				$scope.details = {};
				$scope.approve = {
					user_agreement: 0,
					privacy_policy: 0
				};

				$scope.togglePrivacyPolicy = function() {
					$scope.approve.privacy_policy = $scope.approve.privacy_policy == 0 ? 1 : 0;
				};

				$scope.toggleUserAgreement = function() {
					$scope.approve.user_agreement = $scope.approve.user_agreement == 0 ? 1 : 0;
				};

				$scope.currYear = new Date().getYear() + 1900;

				$scope.continueToPanel = function () {

					if($scope.approve.user_agreement == 0 || $scope.approve.privacy_policy == 0) {
						alert.error(lang.t("You must accept User Agreement and Privacy Policy in order to continue to panel"));
						return;
					}

					api.manageMyAccount({ 
						data: { terms: 1 }, 
						success: function() {
							window.PAGE.system.agreement_panel = false;
							permissions.init(window.PAGE.permissions);
							$location.path('/');
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				api.getMyAccount({ 
					success: function(data) {
						$scope.details = data.info;
					}
				});

			}
		]
	);
});
define('controllers/dashboard',[
	'app',
], function(app) {
	app.controller("dashboard",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert",
			function($rootScope, $scope, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert) {

				$rootScope.$emit('menuItem', 'Dashboard');

				$scope.stats = {
					alerts: 0,
					accounts: 0,
					backup_jobs: 0,
					clone_jobs: 0,
					backups: 0,
					over_quota: 0,
					backup_jobs_running: 0,
					clone_jobs_running: 0
				};


				$scope.loadingStatistics = true;
				$scope.loadingDestinations = false;
				$scope.loadingBackups = false;
				$scope.loadingClones = false;
				$scope.loadingQueues = false;
				$scope.loadingAlerts = false;
				$scope.destroyed = false;

				$scope.lockDestinations = false;
				$scope.lockBackups = false;
				$scope.lockClones = false;

				$scope.queue_summary = {};
				$scope.alerts = [];
				$scope.destinations = [];
				$scope.backups = [];
				$scope.clones = [];
				$scope.queues = [];
				$scope.reloadTimeout = undefined;

				$scope.destinationMeta = meta.new("dashboard_destinations");
				$scope.destinationMetaData = $scope.destinationMeta.getData();
				$scope.destinationMeta.setSortBy("jobs_count");
				$scope.destinationMeta.setSortDirection("asc");
				$scope.destinationMeta.setTotalItems($scope.destinations.length);
				$scope.destinationMeta.setPageSizes([5,10,25]);
				$scope.destinationMeta.setPageSize(5);
				$scope.destinationMeta.setLimit(5);
				$scope.destinationMeta.setMaxPages(1);

				$scope.backupMeta = meta.new("dashboard_backups");
				$scope.backupMetaData = $scope.backupMeta.getData();
				$scope.backupMeta.setSortBy("next_run");
				$scope.backupMeta.setSortDirection("asc");
				$scope.backupMeta.setTotalItems($scope.backups.length);
				$scope.backupMeta.setPageSizes([5,10,25]);
				$scope.backupMeta.setPageSize(5);
				$scope.backupMeta.setLimit(5);
				$scope.backupMeta.setMaxPages(1);

				$scope.cloneMeta = meta.new("dashboard_clones");
				$scope.cloneMetaData = $scope.cloneMeta.getData();
				$scope.cloneMeta.setSortBy("next_run");
				$scope.cloneMeta.setSortDirection("asc");
				$scope.cloneMeta.setTotalItems($scope.clones.length);
				$scope.cloneMeta.setPageSizes([5,10,25]);
				$scope.cloneMeta.setPageSize(5);
				$scope.cloneMeta.setLimit(5);
				$scope.cloneMeta.setMaxPages(1);

				$scope.queueMeta = meta.new("dashboard_queues");
				$scope.queueMetaData = $scope.queueMeta.getData();
				$scope.queueMeta.setSortBy("created");
				$scope.queueMeta.setSortDirection("desc");
				$scope.queueMeta.setTotalItems($scope.queues.length);
				$scope.queueMeta.setPageSizes([5,10,25]);
				$scope.queueMeta.setPageSize(5);
				$scope.queueMeta.setLimit(5);

				$scope.fetchData = function(callback) {

					if(callback === undefined | typeof callback !== 'function') callback = function() {};

					api.getDashboardDetails({
						success: function(data, message) {

							$scope.stats.alerts = data.statistics.total_new_alerts;
							$scope.stats.accounts = data.statistics.total_accounts;
							$scope.stats.backup_jobs = data.statistics.total_backup_jobs;
							$scope.stats.clone_jobs = data.statistics.total_clone_jobs;
							$scope.stats.backups = data.statistics.total_backups;
							$scope.stats.disk_usage = data.statistics.total_disk_usage;
							$scope.stats.backup_jobs_running = data.statistics.total_backup_jobs_running;
							$scope.stats.clone_jobs_running = data.statistics.total_clone_jobs_running;
							$scope.alerts = data.alerts.alerts;
							$scope.queue_summary = data.queue_summary;

							$scope.destinationMeta.setTotalItems(data.destinations.total);
							$scope.destinationMeta.calculate(data.destinations.destinations);
							$scope.destinations = data.destinations.destinations;

							$scope.backupMeta.setTotalItems(data.backup_jobs.total);
							$scope.backupMeta.calculate(data.backup_jobs.jobs);
							$scope.backups = data.backup_jobs.jobs;

							for(var i = 0; i < $scope.backups.length; i++) {
								var names = [];
								var contains = parseInt($scope.backups[i].contains);

								if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
								else if($scope.backups[i].type == consts.BACKUP_TYPE_DIRECTORY) names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
								else {
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
								}

								$scope.backups[i].contains_name = names.join(', ');
							}

							$scope.cloneMeta.setTotalItems(data.clone_jobs.total);
							$scope.cloneMeta.calculate(data.clone_jobs.jobs);
							$scope.clones = data.clone_jobs.jobs;

							for(var i = 0; i < $scope.clones.length; i++) {
								var names = [];
								var contains = parseInt($scope.clones[i].contains);

								if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
								else if($scope.clones[i].type == consts.BACKUP_TYPE_DIRECTORY) names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
								else {
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
								}

								$scope.clones[i].contains_name = names.join(', ');
							}

							$scope.queueMeta.setTotalItems(data.queue.total);
							$scope.queueMeta.calculate(data.queue.groups);

							$scope.queues = [];
							for(var i = 0; i < data.queue.groups.length; i++) {
								var group = data.queue.groups[i];
								if(parseInt(group.items_completed) <= 0 || parseInt(group.items) <= 0) group.items_progress_percentage = 0
								else group.items_progress_percentage = parseInt((parseInt(group.items_completed) / parseInt(group.items)) * 100);
								$scope.queues.push(group);
							}

							callback();
						},
						failed: function (message) {
							alert.error(message);
							callback();
						}
					});
				};

				/*
				$scope.interval = $interval(function () {
					$scope.fetchData();
				}, 10000);

				$scope.$on("$destroy", function() {
					if ($scope.interval === undefined) return;
					$interval.cancel($scope.interval);
					$scope.interval = undefined;
				});
				*/

				$scope.$on('fetch', fetch);

				function fetch() {
					$scope.loadingStatistics = true;
					$scope.fetchData(function() {
						$scope.loadingStatistics = false;
					});
				}

				$scope.reloadData = function() {

					api.getDashboardDetails({
						withLoader: false,
						success: function(data) {

							$scope.stats.alerts = data.statistics.total_new_alerts;
							$scope.stats.accounts = data.statistics.total_accounts;
							$scope.stats.jobs = data.statistics.total_backup_jobs;
							$scope.stats.backups = data.statistics.total_backups;
							$scope.stats.disk_usage = data.statistics.total_disk_usage;
							$scope.stats.jobs_running = data.statistics.total_backup_jobs_running;
							$scope.alerts = data.alerts.alerts;
							$scope.queue_summary = data.queue_summary;

							$scope.listDestinations(false, function () {
								$scope.listBackupJobs(false, function () {
									$scope.listQueueItems(false, function () {
										if($scope.destroyed) return;
										$scope.reloadTimeout = setTimeout($scope.reloadData, 5000);
									});
								});
							});
						}
					});
				};

				$scope.reloadTimeout = setTimeout($scope.reloadData, 5000);
				
				$scope.toggleDestinationStatus = function(destination) {

					if($scope.lockDestinations) return;

					api.manageDestination({ 
						data: { action: 'modify', _id: destination._id, disabled: !destination.disabled },
						success: function(data) {
							destination.disabled = data.disabled;
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.toggleBackupJobStatus = function(job) {

					if($scope.lockBackups) return;

					api.manageBackupJob({ 
						data: { action: 'modify', _id: job._id, disabled: !job.disabled }, 
						success: function(data) {
							job.disabled = data.disabled;
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.toggleCloneJobStatus = function(job) {

					if($scope.lockClones) return;

					api.manageCloneJob({
						data: { action: 'modify', _id: job._id, disabled: !job.disabled },
						success: function(data) {
							job.disabled = data.disabled;
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.listDestinations = function(loading, callback) {
					if(loading === undefined) loading = true;
					if(callback === undefined || typeof callback != 'function') callback = function(){};

					if(!loading) {
						$scope.loadingDestinations = false;
						$scope.lockDestinations = true;
					} else {
						$scope.destinations = [];
						$scope.loadingDestinations = true;
					}

					var sort = {};
					sort[$scope.destinationMeta.getSortBy()] = $scope.destinationMeta.getSortDirectionInt();

					api.listDestinations({
						withLoader: loading,
						data: {
							sort: sort,
							skip: $scope.destinationMeta.getSkip(),
							limit: $scope.destinationMeta.getPageSize()
						}, 
						success: function(data) {
							callback();
							setTimeout(function () { $scope.lockDestinations = false; }, 300);
							$scope.destinationMeta.setTotalItems(data.total);
							$scope.destinationMeta.calculate(data.destinations);
							$scope.destinations = data.destinations;
							$scope.loadingDestinations = false;
						},
						failed: function () {
							callback();
							setTimeout(function () { $scope.lockDestinations = false; }, 300);
							$scope.loadingDestinations = false;
						}
					});
				};

				$scope.listBackupJobs = function(loading, callback) {
					if(callback === undefined || typeof callback != 'function') callback = function(){};

					if(loading !== undefined && !loading) {
						$scope.loadingBackups = false;
						$scope.lockBackups = true;
					} else {
						$scope.backups = [];
						$scope.loadingBackups = true;
					}


					var sort = {};
					sort[$scope.backupMeta.getSortBy()] = $scope.backupMeta.getSortDirectionInt();

					api.listBackupJobs({
						withLoader: loading,
						data: {
							sort: sort,
							skip: $scope.backupMeta.getSkip(),
							limit: $scope.backupMeta.getPageSize()
						}, 
						success: function(data) {
							callback();
							
							setTimeout(function () { $scope.lockBackups = false; }, 300);
	
							$scope.loadingBackups = false;
	
							$scope.backupMeta.setTotalItems(data.total);
							$scope.backupMeta.calculate(data.jobs);
							$scope.backups = data.jobs;
	
							for(var i = 0; i < $scope.backups.length; i++) {
								var names = [];
								var contains = parseInt($scope.backups[i].contains);
	
								if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
								else if($scope.backups[i].type == consts.BACKUP_TYPE_DIRECTORY) names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
								else {
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
								}
	
								$scope.backups[i].contains_name = names.join(', ');
							}
						},
						failed: function () {
							callback();
							setTimeout(function () { $scope.lockBackups = false; }, 300);
							$scope.loadingBackups = false;
						}
					});
				};
				
				$scope.listCloneJobs = function(loading, callback) {
					if(callback === undefined || typeof callback != 'function') callback = function(){};

					if(loading !== undefined && !loading) {
						$scope.loadingClones = false;
						$scope.lockClones = true;
					} else {
						$scope.clones = [];
						$scope.loadingClones = true;
					}


					var sort = {};
					sort[$scope.cloneMeta.getSortBy()] = $scope.cloneMeta.getSortDirectionInt();

					api.listCloneJobs({
						withLoader: loading,
						data: {
							sort: sort,
							skip: $scope.cloneMeta.getSkip(),
							limit: $scope.cloneMeta.getPageSize()
						},
						success: function(data) {
							callback();

							setTimeout(function () { $scope.lockClones = false; }, 300);

							$scope.loadingClones = false;

							$scope.cloneMeta.setTotalItems(data.total);
							$scope.cloneMeta.calculate(data.jobs);
							$scope.clones = data.jobs;

							for(var i = 0; i < $scope.clones.length; i++) {
								var names = [];
								var contains = parseInt($scope.clones[i].contains);

								if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
								else if($scope.clones[i].type == consts.BACKUP_TYPE_DIRECTORY) names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
								else {
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
									if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
								}

								$scope.clones[i].contains_name = names.join(', ');
							}
						},
						failed: function () {
							callback();
							setTimeout(function () { $scope.lockClones = false; }, 300);
							$scope.loadingClones = false;
						}
					});
				};

				$scope.listQueueItems = function(loading, callback) {
					
					if(callback === undefined || typeof callback != 'function') callback = function(){};
					
					if(loading !== undefined && !loading) $scope.loadingQueues = false;
					else {
						$scope.queues = [];
						$scope.loadingQueues = true;
					}

					var sort = {};
					sort[$scope.queueMeta.getSortBy()] = $scope.queueMeta.getSortDirectionInt();

					var type = consts.QUEUE_ITEM_TYPE_BACKUP | consts.QUEUE_ITEM_TYPE_CLONE | consts.QUEUE_ITEM_TYPE_REINDEX;
					if(permissions.canRestoreBackups) type |= consts.QUEUE_ITEM_TYPE_RESTORE;
					if(permissions.canDownloadBackups) type |= consts.QUEUE_ITEM_TYPE_DOWNLOAD;
					if(permissions.isRoot) type |= (consts.QUEUE_ITEM_TYPE_SECURITY | consts.QUEUE_ITEM_TYPE_INTEGRITY_CHECK | consts.QUEUE_ITEM_TYPE_SNAPSHOT_DELETE | consts.QUEUE_ITEM_TYPE_EXTENSION_INSTALLATION | consts.QUEUE_ITEM_TYPE_EXTENSION_QUEUE);

					api.listQueueGroups({
						withLoader: loading,
						data: {
							sort: sort,
							skip: $scope.queueMeta.getSkip(),
							limit: $scope.queueMeta.getPageSize(),
							type: type
						}, 
						success: function(data) {
							callback();
							$scope.loadingQueues = false;
							$scope.queueMeta.setTotalItems(data.total);
							$scope.queueMeta.calculate(data.groups);
	
							$scope.queues = [];
							for(var i = 0; i < data.groups.length; i++) {
								var group = data.groups[i];
								if(parseInt(group.items_completed) <= 0 || parseInt(group.items) <= 0) group.items_progress_percentage = 0
								else group.items_progress_percentage = parseInt((parseInt(group.items_completed) / parseInt(group.items)) * 100);
								$scope.queues.push(group);
							}
						},
						failed: function () {
							callback();
							$scope.loadingQueues = false;
						}
					});
				};

				$scope.$on("$destroy", function() {
					$scope.destroyed = true;
					if ($scope.reloadTimeout === undefined) return;
					clearTimeout($scope.reloadTimeout);
					$scope.reloadTimeout = undefined;
				});

				$timeout(fetch);
			}
		]
	);
});


define('controllers/alerts',['app'], function(app) {
	app.controller("alerts",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "consts", "lang", "confirm", "alert",
			function ($rootScope, $scope, $location, $timeout, api, meta, consts, lang, confirm, alert) {
				$rootScope.$emit('menuItem', 'Alerts');

				$scope.alerts = [];
				$scope.loadingAlerts = false;
				$scope.saveing = false;
				$scope.filter = 0;
				$scope.filterOptions = [
					{ label: lang.t('All Alerts'), value: 0 },
					{ label: lang.t('Information Alerts'), value: consts.ALERT_LEVEL_INFO },
					{ label: lang.t('Warning Alerts'), value: consts.ALERT_LEVEL_WARNING },
					{ label: lang.t('Critical Alerts'), value: consts.ALERT_LEVEL_CRITICAL }
				];

				meta = meta.new("alerts");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["created","message","owner","level"]);
				meta.setTotalItems($scope.alerts.length);

				$scope.clearAlerts = function () {

					if($scope.saveing) return;
					$scope.saveing = true;

					confirm.open({
						message: lang.t("All alerts will be deleted and no future notifications will be sent"),
						confirm: function () {
							api.clearAlerts({
								success: function(data, message) {
									$scope.saveing = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};
				
				$scope.fetch = function() {

					$scope.loadingAlerts = true;

					var find = {};
					if(parseInt($scope.filter) > 0) find.level = parseInt($scope.filter);

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: find,
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.alerts = [];

					api.listAlerts({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.alerts);
							$scope.alerts = data.alerts;
							$scope.loadingAlerts = false;
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/accounts',['app'], function(app) {
	app.controller("accounts",
		["$rootScope", "$scope", "$location", "$timeout", "api", "lang", "meta", "confirm", "alert", "consts", "util", "permissions", "popup",
			function ($rootScope, $scope, $location, $timeout, api, lang, meta, confirm, alert, consts, util, permissions, popup) {

				$rootScope.$emit('menuItem', 'Accounts');

				$scope.accounts = [];
				$scope.tags = {};
				$scope.loadingAccounts = false;
				$scope.deleteTag = false;
				$scope.filter = '';

				if(permissions.isRoot) {
					$scope.filterOptions = [
						{label: lang.t("No Tags Filter"), value: ""},
						{label: lang.t("Without Any Tags"), value: "none"}
					];
				} else {
					$scope.filterOptions = [];
				}

				$scope.loaders = {
					quota: false,
					snapshot: false
				};

				var metaAcct = meta.new("accounts");
				$scope.meta = metaAcct;
				$scope.metaData = metaAcct.getData();

				metaAcct.setSortReverse(false);
				if(!metaAcct.getSortBy()) metaAcct.setSortBy("username");
				if(!metaAcct.getSortDirection()) metaAcct.setSortDirection("asc");
				metaAcct.setSortFields(["username", "owner"]);
				metaAcct.setTotalItems($scope.accounts.length);

				$scope.manageTags = function(account) {
					popup.open({
						template: 'tagsSelection',
						resolve: {
							tags: function() { return account.tags; },
							type: function () { return consts.TAG_TYPE_ACCOUNT; }
						}
					}).result.then(function(selected) {

						account.deletetags = true;
						api.manageAccount({ 
							data: { _id: account._id, tags: selected }, 
							success: function () {
								account.deletetags = false;
								account.tags = selected;
							},
							failed: function (message) {
								account.deletetags = false;
								alert.error(message);
							}
						});

					}, function () {});
				};

				$scope.removeTag = function(account, index) {

					if($scope.deleteTag) return;
					$scope.deleteTag = true;

					confirm.open({
						message: lang.t("This tag will be removed from this account"),
						confirm: function () {
							account.deletetags = true;

							var tags = util.duplicateObject(account.tags);
							tags.splice(index, 1);

							api.manageAccount({ 
								data: { _id: account._id, tags: tags }, 
								success: function () {
									$scope.deleteTag = false;
									account.deletetags = false;
									account.tags.splice(index, 1);
								},
								failed: function (message) {
									$scope.deleteTag = false;
									account.deletetags = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.deleteTag = false;
						}
					});
				};

				$scope.reassign = function (account) {
					popup.open({
						size: "lg",
						template: 'accountReassign',
						resolve: {
							account_details: function() { return account; }
						}
					}).result.then(function(refresh) {
						if(refresh) $scope.fetch();
					}, function(){
						$scope.fetch();
					});
				};

				$scope.createSnapshot = function(account) {

					if($scope.loaders.snapshot) return;
					$scope.loaders.snapshot = true;

					confirm.open({
						message: lang.t("Are you sure you want to create backup on demand for this account?"),
						confirm: function () {

							api.createBackupOnDemand({
								data: { account_id: account._id },
								success: function(data, message) {
									$scope.loaders.snapshot = false;
									alert.success(message);
								},
								failed: function(message) {
									$scope.loaders.snapshot = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.loaders.snapshot = false;
						}
					});
				};

				$scope.viewBackups = function (account) {
					popup.open({
						size: "xl",
						template: 'accountBackups',
						resolve: {
							account: function() { return account; }
						}
					}).result.then(function(refresh) {
						if(refresh) $scope.fetch();
					}, function(){});
				};

				$scope.viewDownloads = function (account) {
					popup.open({
						size: "xl",
						template: 'accountDownloads',
						resolve: {
							account: function() { return account; }
						}
					}).result.then(function() {}, function(){});
				};

				$scope.fetch = function() {

					$scope.loadingAccounts = true;

					var apiParams = {
						sort: {},
						skip: metaAcct.getSkip(),
						limit: metaAcct.getPageSize(),
						find: {},
						filter: metaAcct.getFilter()
					};

					apiParams.sort[metaAcct.getSortBy()] = metaAcct.getSortDirectionInt();
					if($scope.filter) apiParams.find.tags = $scope.filter;

					$scope.accounts = [];

					api.listAccounts({ 
						data: apiParams, 
						success: function(data) {
							metaAcct.setTotalItems(data.total);
							metaAcct.calculate(data.accounts);
							$scope.accounts = data.accounts;
							$scope.loadingAccounts = false;
						}
					});
				};

				if(permissions.isRoot) {
					api.listTags({ 
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) {
								$scope.filterOptions.push({label: data.tags[i].name, value: data.tags[i]._id});
								$scope.tags[data.tags[i]._id] = data.tags[i];
							}
							$timeout($scope.fetch);
						}
					});
				} else {
					$timeout($scope.fetch);
				}
	}]);
});


define('controllers/accountsOrphans',['app'], function(app) {
	app.controller("accountsOrphans",
		["$rootScope", "$scope", "$location", "$timeout", "api", "lang", "meta", "popup", "permissions", "consts",
			function ($rootScope, $scope, $location, $timeout, api, lang, meta, popup, permissions, consts) {

				$rootScope.$emit('menuItem', 'Accounts');

				$scope.accounts = [];
				$scope.tags = {};
				$scope.loadingAccounts = false;
				$scope.deleteTag = false;
				$scope.filter = '';

				if(permissions.isRoot) {
					$scope.filterOptions = [
						{label: lang.t("No Tags Filter"), value: ""},
						{label: lang.t("Without Any Tags"), value: "none"}
					];
				} else {
					$scope.filterOptions = [];
				}

				$scope.loaders = {
					quota: false,
				};

				var metaAcct = meta.new("accountsOrphans");
				$scope.meta = metaAcct;
				$scope.metaData = metaAcct.getData();

				metaAcct.setSortReverse(false);
				if(!metaAcct.getSortBy()) metaAcct.setSortBy("username");
				if(!metaAcct.getSortDirection()) metaAcct.setSortDirection("asc");
				metaAcct.setSortFields(["username", "owner"]);
				metaAcct.setTotalItems($scope.accounts.length);

				$scope.manageTags = function(account) {
					popup.open({
						template: 'tagsSelection',
						resolve: {
							tags: function() { return account.tags; },
							type: function () { return consts.TAG_TYPE_ACCOUNT; }
						}
					}).result.then(function(selected) {

						account.deletetags = true;
						api.manageAccount({
							data: { _id: account._id, tags: selected },
							success: function () {
								account.deletetags = false;
								account.tags = selected;
							},
							failed: function (message) {
								account.deletetags = false;
								alert.error(message);
							}
						});

					}, function () {});
				};

				$scope.removeTag = function(account, index) {

					if($scope.deleteTag) return;
					$scope.deleteTag = true;

					confirm.open({
						message: lang.t("This tag will be removed from this account"),
						confirm: function () {
							account.deletetags = true;

							var tags = util.duplicateObject(account.tags);
							tags.splice(index, 1);

							api.manageAccount({
								data: { _id: account._id, tags: tags },
								success: function () {
									$scope.deleteTag = false;
									account.deletetags = false;
									account.tags.splice(index, 1);
								},
								failed: function (message) {
									$scope.deleteTag = false;
									account.deletetags = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.deleteTag = false;
						}
					});
				};

				$scope.viewBackups = function (account) {

					popup.open({
						size: "xl",
						template: 'accountBackups',
						resolve: {
							account: function() { return account; }
						}
					}).result.then(function(refresh) {
						if(refresh) $scope.fetch();
					}, function(){});

				};

				$scope.viewDownloads = function (account) {

					popup.open({
						size: "xl",
						template: 'accountDownloads',
						resolve: {
							account: function() { return account; }
						}
					}).result.then(function() {}, function(){});

				};

				$scope.fetch = function() {

					$scope.loadingAccounts = true;

					var apiParams = {
						sort: {},
						skip: metaAcct.getSkip(),
						limit: metaAcct.getPageSize(),
						find: {},
						filter: metaAcct.getFilter()
					};

					apiParams.sort[metaAcct.getSortBy()] = metaAcct.getSortDirectionInt();
					if($scope.filter) apiParams.find.tags = $scope.filter;
					apiParams.orphan = 1;

					$scope.accounts = [];

					api.listAccounts({ 
						data: apiParams, 
						success: function(data) {
							metaAcct.setTotalItems(data.total);
							metaAcct.calculate(data.accounts);
							$scope.accounts = data.accounts;
							$scope.loadingAccounts = false;
						}
					});
				};

				if(permissions.isRoot) {
					api.listTags({
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } },
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) {
								$scope.filterOptions.push({label: data.tags[i].name, value: data.tags[i]._id});
								$scope.tags[data.tags[i]._id] = data.tags[i];
							}
							$timeout($scope.fetch);
						}
					});
				} else {
					$timeout($scope.fetch);
				}
	}]);
});


define('controllers/accountManage',['app'], function(app) {
	
	app.controller("accountManage",
		["$rootScope", "$scope", "$routeParams", "$q", "$location", "$timeout", "api", "meta", "util", "lang", "confirm", "alert", "consts", "popup",
			function ($rootScope, $scope, $routeParams, $q, $location, $timeout, api, meta, util, lang, confirm, alert, consts, popup) {
				$rootScope.$emit('menuItem', 'Accounts');

				if(!$routeParams.id) $location.path("/");

				$scope.tags = {};
				$scope.details = {
					email: '',
					max_snapshots: '',
					queue_priority: ''
				};

				$scope.saveData = util.duplicateObject($scope.details);

				$scope.saveing = false;
				$scope.changed = false;
				$scope.cancelled = false;

				$scope.queuePriorities = [
						{ _id: '', name: lang.t('Default') }
				];

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.searchTags = function(query) {

					if(!query) return [];

					var deferred = $q.defer();

					api.listTags({ 
						data: { filter: query, sort: { name: 1 }, find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function(data) {

							var results = [];
							for(var i = 0; i < data.tags.length; i++) {
								var tag = data.tags[i];
								if($scope.saveData.tags.indexOf(tag._id) >= 0) continue;
								results.push(tag);
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.selectItem = function(item, obj) {
					if(item === undefined) return;
					$scope.saveData.tags.push(item._id);
					obj.searchItemText = '';
				};

				$scope.manageTags = function() {

					popup.open({
						template: 'tagsSelection',
						scope: $scope,
						resolve: {
							tags: function() { return $scope.saveData.tags; },
							type: function () { return consts.TAG_TYPE_ACCOUNT; }
						}
					}).result.then(function(selected) {
						$scope.saveData.tags = selected;
					}, function () {});

				};

				$scope.resetEncryptionKey = function() {

					confirm.open({
						message: lang.t("Once you reset the account encryption key, ALL BACKUPS becomes inaccessible and will be deleted."),
						confirmLabel: lang.t("Delete Encryption Key"),
						confirm: function () {
							api.resetEncryptionKey({ 
								data: { username: $scope.details.username }, 
								success: function (data, message) {
									$scope.details.secret_key = false;
									alert.success(message); 
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};


				$scope.manageExcludes = function () {

					popup.open({
						size: "lg",
						template: 'accountExcludeListSelection',
						resolve: {
							account: function() { return $scope.details; }
						}
					}).result.then(function() {}, function(){});

				};

				$scope.fetchQueuePriorities = function() {

					api.listQueuePriorities({ 
						success: function (data) {
							var priorities = data.priorities;
							for(var i=0; i< priorities.length; i++ ){
								$scope.queuePriorities.push(priorities[i]);
							}
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/accounts');
				};

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);

					api.manageAccount({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.details.email = $scope.saveData.email;
							$scope.details.max_snapshots = $scope.saveData.max_snapshots;
							//$location.path('/accountManage/' + $scope.details._id);
							if(!apply) $location.path('/accounts');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				$scope.fetchAccountData = function(id) {
					api.getAccount({ 
						data: { _id: id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});
				};

				$scope.fetchTags = function() {
					api.listTags({ 
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) $scope.tags[data.tags[i]._id] = data.tags[i];
						}
					});
				};

				$timeout(function () {
					$scope.fetchTags();
					$scope.fetchQueuePriorities();
					$scope.fetchAccountData($routeParams.id);
				});
			}
		]
	);
});


define('controllers/accountReassign',['app'], function(app) {
	
	app.controller("accountReassign",
		["$uibModalInstance", "$scope", "$location", "$timeout", "api", "meta", "util", "lang", "confirm", "alert", "account_details",
			function ($uibModalInstance, $scope, $location, $timeout, api, meta, util, lang, confirm, alert, account_details) {

				$scope.saveing = false;
				$scope.account = account_details;
				$scope.accounts = [];
				$scope.loadingAccounts = false;
				$scope.refresh = false;

				var metaAcct = meta.new("account_reassign");
				$scope.meta = metaAcct;
				$scope.metaData = metaAcct.getData();

				metaAcct.setSortReverse(false);
				if(!metaAcct.getSortBy()) metaAcct.setSortBy("active");
				if(!metaAcct.getSortDirection()) metaAcct.setSortDirection("desc");
				metaAcct.setPageSizes([5,10]);
				metaAcct.setPageSize(10);
				metaAcct.setSortFields(["active"]);
				metaAcct.setTotalItems($scope.accounts.length);

				$scope.reassignAccount = function(account) {
					if($scope.saveing) return;
					$scope.saveing = true;

					confirm.open({
						message: lang.t("This account will be reassign to different account data, including backups and personal information."),
						confirm: function () {
							api.reassignAccount({ 
								data: { _id: account._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.refresh = true;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingAccounts = true;

					var apiParams = {
						sort: {},
						skip: metaAcct.getSkip(),
						limit: metaAcct.getPageSize(),
						find: {},
						filter: metaAcct.getFilter()
					};

					apiParams.account = $scope.account.username;
					apiParams.sort[metaAcct.getSortBy()] = metaAcct.getSortDirectionInt();

					$scope.accounts = [];

					api.listAssignableAccounts({ 
						data: apiParams, 
						success: function(data) {
							metaAcct.setTotalItems(data.total);
							metaAcct.calculate(data.accounts);
							$scope.accounts = data.accounts;
							$scope.loadingAccounts = false;
						},
						failed: function () {
							$location.path('/accounts');
						}
					});
				};

				$timeout($scope.fetch);

				$scope.ok = function () { $uibModalInstance.close($scope.refresh); };

			}
		]
	);
});


define('controllers/accountExcludeListSelection',['app'], function(app) {

	app.controller('accountExcludeListSelection',
		["$uibModalInstance", "$scope", "alert", "lang", "api", "consts", "popup", "account",
			function($uibModalInstance, $scope, alert, lang, api, consts, popup, account) {

				$scope.account = account;
				$scope.excludes = {};
				$scope.excluderow = '';
				$scope.selected_job = "global";
				$scope.jobs = [
					{ _id: 'global', name: "- " + lang.t("All Backup Jobs (Global)") + " -" }
				];

				api.getAccountExcludeList({ 
					data: { _id: account._id }, 
					success: function (data) {
						$scope.excludes = data;
					}
				});

				api.listBackupJobs({ 
					data: { find: { type: consts.BACKUP_TYPE_ACCOUNT } }, 
					success: function (data) {
						for(var i = 0; i < data.jobs.length; i++) {
							$scope.jobs.push(data.jobs[i]);
							if($scope.excludes[data.jobs[i]._id] === undefined) $scope.excludes[data.jobs[i]._id] = [];
						}
					}
				});

				var checkDuplicateItems = function(value) {
					var withoutTrailing = value.replace(/\/+$/, '');
					var withTrailing = withoutTrailing + '/';
					return ($scope.excludes[$scope.selected_job].indexOf(withoutTrailing) >= 0 || $scope.excludes[$scope.selected_job].indexOf(withTrailing) >= 0);
				};

				var validateListPath = function (path) {
					if(!path.trim()) return false;
					return !consts.PATH_FILTER_PATTERNS.test(path);
				};

				$scope.addMultiListRow = function() {

					$scope.listTitle = lang.t("Directories and Files to exclude");
					$scope.listData = $scope.excludes[$scope.selected_job].join("\n");

					$scope.listUIB = popup.open({
						size: "xl",
						template: 'listSelection',
						scope: $scope,
						noController: true
					});
					
					$scope.listUIB.result.then(function(records) {
						while($scope.excludes[$scope.selected_job].length) $scope.excludes[$scope.selected_job].pop();
						records = records.split("\n");
						var invalidPaths = [];
						var duplicatePaths = [];
						for(var i = 0; i < records.length; i++) {
							if(checkDuplicateItems(records[i])) duplicatePaths.push(records[i]);
							else if(validateListPath(records[i])) {
								if ($scope.excludes[$scope.selected_job].indexOf(records[i]) < 0 ) $scope.excludes[$scope.selected_job].push(records[i]);
							}
							else invalidPaths.push(records[i]);
						}

						if(invalidPaths.length) alert.error(lang.t('The following paths ("%s") is invalid. The path must start with a "/" and can\'t have trailing "/"' + (type === 'include' ? ', also patterns are not allowed.' : '.'), invalidPaths.join(", ") ))
						if(duplicatePaths.length) alert.error(lang.t('The provided path(s) ("%s") already exists on the list.', duplicatePaths.join(", ")));
					}, function () { });
				};

				$scope.addListRow = function() {

					var path = $scope.excluderow.trim();

					if(checkDuplicateItems(path)){
						alert.error(lang.t('The provided path ("%s") already exists on the list.', path));
					} else if(validateListPath(path)) {
						$scope.excludes[$scope.selected_job].push(path);
					} else {
						alert.error(lang.t('The provided path ("%s") is invalid. The path must start with a "/"', path ));
					}

					$scope.excluderow = '';
				};

				$scope.ok = function () {
					api.manageAccountExcludeList({ 
						data: { _id: $scope.account._id, excludes: $scope.excludes }, 
						success: function (data, message) {
							$uibModalInstance.close();
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
	}]);

});


define('controllers/modifyDatabasesExcludes',['app'], function(app) {
	app.controller('modifyDatabasesExcludes',
		["$uibModalInstance", "$rootScope", "$scope", "$routeParams", "$location", "permissions", "lang", "db_excludes",
			function($uibModalInstance, $rootScope, $scope, $routeParams, $location, permissions, lang, db_excludes) {

				$scope.dbExcludesSections = [
					{ _id: 'mysql',			name: lang.t('MySQL'),		template: 'modifyMySQLExcludes',		icon: 'fa-database', 	hidden: false },
					{ _id: 'postgresql',	name: lang.t('PostgreSQL'),	template: 'modifyPostgreSQLExcludes',	icon: 'fa-database', 	hidden: false },
					{ _id: 'mongodb',		name: lang.t('MongoDB'),	template: 'modifyMongoDBExcludes',		icon: 'fa-database', 	hidden: false },
				];

				$scope.getDBExcludesSection = function (section_id) {
					for(var i = 0; i < $scope.dbExcludesSections.length; i++) {
						if($scope.dbExcludesSections[i]._id === section_id) {
							return $scope.dbExcludesSections[i];
						}
					}

					return $scope.dbExcludesSections[0];
				};

				$scope.loadDBExcludesSection = function (section) {
					$scope.currentDBExcludesSection = section;
					$scope.dbExcludesSection = $scope.includePath(section.template);
				};

				$scope.loadDBExcludesSection($scope.getDBExcludesSection($routeParams.section ? $routeParams.section : 'mysql'));

				if (db_excludes === undefined)
					db_excludes = { mysql_exclude_db_by_size: 0, postgresql_exclude_db_by_size: 0, mongodb_exclude_db_by_size: 0 };

				$scope.excludes = {
					mysql_exclude_db_by_size: db_excludes.mysql_exclude_db_by_size,
					postgresql_exclude_db_by_size: db_excludes.postgresql_exclude_db_by_size,
					mongodb_exclude_db_by_size: db_excludes.mongodb_exclude_db_by_size,
				};

				$scope.ok = function () {
					$uibModalInstance.close($scope.excludes);
				};
		
				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
	}]);

});


define('controllers/destinations',['app'], function(app) {
	app.controller("destinations",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "lang", "alert", "confirm", "consts",
			function ($rootScope, $scope, $location, $timeout, api, meta, lang, alert, confirm, consts) {
				$rootScope.$emit('menuItem', 'Destinations');

				$scope.loadingDestinations = false;
				$scope.destinations = [];
				$scope.checkReindexTimeout = undefined;
				$scope.types = {};
				$scope.filter = '';
				$scope.filterOptions = [{ label: lang.t('All Destinations'), value: '' }];
				$scope.saveing = false;
				$scope.jobs = {};

				$scope.loaders = {
					state: false,
					validation: false,
					dr: false,
					hide: false,
					delete: false,
					reindex: false,
					speed: false
				};

				meta = meta.new("destinations");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","owner","engine","count","disabled","dr"]);
				meta.setTotalItems($scope.destinations.length);

				$scope.onClickDelete = function(destination) {

					if($scope.saveing) return;

					if(destination.jobs_count > 0) {
						alert.error(lang.t("This destination has an assigned jobs, Please remove those jobs before deleting this destination."));
						return false;
					}

					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This destination will be permanently deleted!"),
						confirm: function () {
							api.deleteDestination({ 
								data: { _id: destination._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				function apiDestination(params, callback) {
					if($scope.saveing) return;
					$scope.saveing = true;
					if(!params === undefined) params = {};
					api.manageDestination({ 
						data: params, 
						success: function(data, message) {
							$scope.saveing = false;
							if(callback !== undefined) callback({ success: true, data: data, message: message });
						},
						failed: function (message) {
							alert.error(message);
							if(callback !== undefined) callback({ success: false, data: {}, message: message });
						}
					});
				}

				$scope.measureSpeed = function (destination) {
					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.speed = true;

					confirm.open({
						message: lang.t("JetBackup will use a 100MB file for the speed test, and depending on your destination, charges may apply."),
						confirm: function () {
							api.measureDestinationSpeed({
								data: { _id: destination._id },
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.speed = false;
									alert.success(message);
									destination.speed = data.speed;
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.speed = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.speed = false;
						}
					});


				};
				
				$scope.reindex = function(destination) {
					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.reindex = true;

					confirm.open({
						message: lang.t("All running processes (backup, restore and etc) related to this destination will be aborted"),
						confirm: function () {
							api.reindexDestination({ 
								data: { _id: destination._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.reindex = false;
									alert.success(message);
									destination.reindex = true;
									$scope.checkReindex();
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.reindex = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.reindex = false;
						}
					});
				};

				$scope.toggleDR = function(destination) {
					$scope.loaders.dr = true;
					var dr = !destination.dr;
					apiDestination({
						_id: destination._id,
						action: 'modify',
						dr: dr
					}, function(response) {
						$scope.loaders.dr = false;
						if(response.success) destination.dr = dr;
					});
				};

				$scope.toggleStatus = function(destination) {
					$scope.loaders.state = true;
					var disabled = !destination.disabled;

					if(!disabled && destination.type !== 'Clones') {

						var model = confirm.open({
							message: lang.t("WARNING: By Enabling the Destination you are also enabling automated tasks to run in the background for this destination. This could result in backups being cleaned using the Manual Backups TTL or Orphan Backups TTL settings. Are you sure you want to enable and perform background tasks on the destination?"),
							buttons: [
								{
									label: lang.t("Change Settings"),
									class: 'btn-primary',
									click: function () {
										$location.path("/settings");
										model.dismiss();
									}
								}
							],
							confirm: function () {

								if($scope.saveing) return;
								$scope.saveing = true;

								api.manageDestinationState({
									data: { 
										_id: destination._id,
										disabled: disabled
									},
									success: function(data, message) {
										$scope.saveing = false;
										$scope.loaders.state = false;
										destination.disabled = disabled;
										alert.success(message);
									},
									failed: function (message) {
										$scope.saveing = false;
										$scope.loaders.state = false;
										alert.error(message);
									}
								});
							},
							cancel: function () {
								$scope.loaders.state = false;
							}
						});

					} else {

						if($scope.saveing) return;
						$scope.saveing = true;

						api.manageDestinationState({
							data: {
								_id: destination._id,
								disabled: disabled
							},
							success: function(data, message) {
								$scope.saveing = false;
								$scope.loaders.state = false;
								destination.disabled = disabled;
								alert.success(message);
							},
							failed: function (message) {
								$scope.saveing = false;
								$scope.loaders.state = false;
								alert.error(message);
							}
						});
					}
				};

				$scope.toggleHidden = function(destination) {
					$scope.loaders.hide = true;
					var hidden = !destination.hidden;
					apiDestination({
						_id: destination._id,
						action: 'modify',
						hidden: hidden
					}, function(response) {
						$scope.loaders.hide = false;
						if(response.success) destination.hidden = hidden;
					});
				};

				$scope.validateDestination = function(destination) {
					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.validation = true;

					api.validateDestination({ 
						data: { _id: destination._id }, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.loaders.validation = false;
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							$scope.loaders.validation = false;
							alert.error(message);							
						}
					});
				};

				$scope.listDestinations = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function(){};

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					if($scope.filter) apiParams.find.type = $scope.filter;
					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listDestinations({ 
						data: apiParams, 
						success: function (data, message) { callback({ success: true, data: data, message: message}); },
						failed: function (data, message) { callback({ success: false, data: data, message: message}); }
					});
				};

				$scope.fetch = function() {
					if($scope.loadingDestinations) return;
					$scope.loadingDestinations = true;
					$scope.listDestinations(function (response) {

						$scope.destinations = [];
						$scope.loadingDestinations = false;
						meta.setTotalItems(response.data.total);
						meta.calculate(response.data.destinations);

						var reindex = false;
						for(var i = 0; i < response.data.destinations.length; i++) {
							var destination = response.data.destinations[i];
							$scope.destinations.push(destination);
							if(destination.reindex) reindex = true;
						}

						if(reindex) $scope.checkReindex();
					});
				};

				$scope.getDestination = function(destination_id) {
					for(var i = 0; i < $scope.destinations.length; i++) {
						if($scope.destinations[i]._id == destination_id) return $scope.destinations[i];
					}
					return null;
				};

				$scope.checkReindex = function() {
					$scope.listDestinations(function (response) {

						var reindex = false;
						for(var i = 0; i < response.data.destinations.length; i++) {
							var destination_new = response.data.destinations[i];
							if(destination_new.reindex) reindex = true;

							var destination = $scope.getDestination(destination_new._id);
							if(destination) destination.reindex = destination_new.reindex;
						}

						if(reindex) $scope.checkReindexTimeout = setTimeout($scope.checkReindex, 3000);
					});
				};

				$scope.$on('$destroy', function() {
					if(!$scope.checkReindexTimeout) return;
					clearTimeout($scope.checkReindexTimeout);
					$scope.checkReindexTimeout = null;
				});


				api.listDestinationTypes({
					/*data: {
						types: consts.DESTINATION_JOB_TYPE_BACKUP
					},*/
					success: function (data) {
						$scope.types = data;
						for(var i = 0; i < data.types.length; i++) {
							$scope.filterOptions.push({ label: consts.DESTINATION_JOB_TYPE_NAMES[data.types[i].type] + ' - ' + data.types[i].name, value: data.types[i].key });
						}
					}
				});

				api.listBackupJobs({ 
					success: function (data) {
						for(var i = 0; i < data.jobs.length; i++) {
							var job = data.jobs[i];
	
							for(var j = 0; j < job.destination.length; j++) {
								if($scope.jobs[job.destination[j]] === undefined) $scope.jobs[job.destination[j]] = [];
								$scope.jobs[job.destination[j]].push(job);
							}
						}
					}
				});

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/destinationManage',['app'], function(app) {
	app.controller("destinationManage",
		["$rootScope", "$scope", "$routeParams", "$q", "$location", "$timeout", "api", "meta", "util", "confirm", "permissions", "lang", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $q, $location, $timeout, api, meta, util, confirm, permissions, lang, consts, alert) {
				$rootScope.$emit('menuItem', 'Destinations');

				$scope.details = {};
				$scope.saveData = {
					job_type: consts.DESTINATION_JOB_TYPE_BACKUP,
					type: '',
					owner: $scope.loggedAccount._id,
					owner_name: $scope.loggedAccount.username,
					disk_limit: 95,
					threads: 150,
					readonly: 0,
					options: {}
				};

				$scope.forks = {
					backup: 0,
					queueable: 0,
					system: 0,
					total: 0,
				};

				$scope.autocomplete = { accountText: $scope.saveData.owner_name };

				$scope.saveing = false;
				$scope.changed = true;
				$scope.forkThreads = 0;
				//$scope.cancelled = false;
				$scope.types = {};
				$scope.types[consts.DESTINATION_JOB_TYPE_BACKUP] = [];
				$scope.types[consts.DESTINATION_JOB_TYPE_CLONE] = [];
				$scope.publicDir = '';
				$scope.plugin = {};
				$scope.plugin_available = {};
				$scope.plugins_available = {};
				$scope.installing = false;
				$scope.experimental = '';

				$scope.disklimits = [
					{ label: lang.t("Disabled"), value: 0 },
					{ label: "50%", value: 50 },
					{ label: "55%", value: 55 },
					{ label: "60%", value: 60 },
					{ label: "65%", value: 65 },
					{ label: "70%", value: 70 },
					{ label: "75%", value: 75 },
					{ label: "80%", value: 80 },
					{ label: "85%", value: 85 },
					{ label: "90%", value: 90 },
					{ label: "95%", value: 95 }
				];

				$scope.isAvailableDestinations = function() {
					return $scope.saveData.type && $scope.saveData.type.indexOf('AvailableDestinations') >= 0;
				};

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.saveData.owner = account._id;
					$scope.saveData.owner_name = account.username;
					$scope.autocomplete.accountText = account.username;
					var activeElement = document.activeElement;
					if (activeElement) activeElement.blur();
				};

				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.resetOptions = function () {
					//$scope.saveData.options = {};
					$scope.options = {
						disklimit: true,
						threads: false
					};
				};
				
				$scope.loadTemplate = function(type) {
					if(!type) return;

					if(type.indexOf('::') >= 0) {
						var parts = type.split('::');
						type = parts[0];
						$scope.plugin_available = $scope.plugins_available[parts[1]];
					}

					$scope.resetOptions();

					switch(type) {
						case 'AvailableDestinations':
							$scope.destinationType = $scope.includePath('destinations/' + type);
							$scope.experimental = $scope.plugin_available.experimental !== undefined ? $scope.plugin_available.experimental : '';
						break;

						default:
							if($scope.plugin[type] === undefined) return;
							lang.setDefaultNS('plugins-destination-' + type);
							app.registerPluginController($scope.plugin[type], function(path) {
								$scope.publicDir = path;
								$scope.destinationType = $scope.publicDir + '/view.htm?v=' + $scope.plugin[type].version;
								$scope.experimental = $scope.plugin[type].experimental;
							});
						break;
					}
				};

				$scope.loadDestinationType = function(resetOptions) {
					if(resetOptions === undefined) resetOptions = false;
					if(resetOptions) $scope.saveData.options = {};
					$scope.loadTemplate($scope.saveData.type);
				};

				$scope.toggleEngine = function(details) {
					if(details === undefined) return;
					if(details.checked) details.engine = 1;
					return details.checked;
				};

				$scope.resetOptions();

				$scope.$on('options', function (event, options) {
					for(var key in options) $scope.options[key] = options[key];
				});

				$scope.$watch("saveData.job_type", function(){
					if($routeParams.id) return;
					
					if($scope.types[$scope.saveData.job_type][0] !== undefined) {
						$scope.details.type = $scope.types[$scope.saveData.job_type][0].value;
						$scope.saveData.type = $scope.types[$scope.saveData.job_type][0].value;
						$scope.loadDestinationType();
					} else {
						$scope.details.type = '';
						$scope.saveData.type = '';
					}
				}, true);

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
					$scope.forkThreads = $scope.forks.total > 0 ? Math.ceil($scope.saveData.threads / $scope.forks.total) : 0;
				}, true);

				$scope.$on('$destroy', function() {
					if(!$scope.changed || $scope.cancelled || $scope.disasterRecovery) return;

					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirm: $scope.saveChanges,
						cancelLabel: lang.t("Disregard Changes"),
						confirmLabel: lang.t("Save"),
					});
				});

				$scope.cancel = function() {
					//$scope.cancelled = true;
					$location.path('/destinations');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function(key) {
						return ($scope.details._id === undefined && key === 'type');
					});

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageDestination({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
	
							if(callback === undefined) {
								if(apply) $location.path('/destinationManage/' + data._id);
								else $location.path('/destinations');
								alert.success(message);
							}

							if(callback !== undefined && typeof callback === 'function') callback();

						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
							if(callback !== undefined && typeof callback === 'function') callback();
						}
					});
				};

				$scope.installDestination = function() {

					if($scope.installing) return;
					$scope.installing = true;

					confirm.open({
						message: lang.t("This destination will be installed on this server!"),
						confirm: function () {
							api.installPlugin({ 
								data: { package_id: $scope.plugin_available._id, disabled: 0 }, 
								success: function (data, message) {
									$scope.installing = false;

									//$scope.installed_plugin = data;
									$scope.plugin_available = {};
	
									$scope.loadDestinations(function () {
										$scope.saveData.type = data.code;
										$scope.loadDestinationType();
										alert.success(message);
									});
								},
								failed: function (message) {
									$scope.installing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.installing = false;
						}
					});
				};

				$scope.loadDestinations = function(callback) {

					if(callback === undefined || typeof callback !== 'function') callback = function(){};
					
					$scope.types[consts.DESTINATION_JOB_TYPE_BACKUP] = [];
					$scope.types[consts.DESTINATION_JOB_TYPE_CLONE] = [];
					$scope.plugins_available = {};

					api.listDestinationTypes({ 
						success: function (data) {

							for(var i = 0; i < data.types.length; i++) {
	
								var type = data.types[i];
								if((type.key == 'Local' || type.key == 'Localv2') && !permissions.isRoot) continue;
	
								$scope.types[type.type].push({ label: type.name + (type.experimental ? " - " + lang.t("Experimental") : ''), value: type.key, group: lang.t('Installed Destinations') });
								$scope.plugin[type.key] = {
									type: consts.PLUGIN_TYPE_DESTINATION,
									code: type.key,
									job_type: type.type,
									version: type.version,
									experimental: type.experimental
								};
	
								if(!$scope.details.type && !$routeParams.id) {
									$scope.details.type = type.key;
									$scope.saveData.type = type.key;
									$scope.loadDestinationType();
								}

							}

							api.listPackagesAvailable({ 
								data: { find: { type: consts.PLUGIN_TYPE_DESTINATION } }, 
								success: function(data) {
									for(var i = 0; i < data.packages.length; i++) {
										var pkg = data.packages[i];
										$scope.plugins_available[pkg.code] = pkg;
										$scope.types[consts.DESTINATION_JOB_TYPE_BACKUP].push({ label: lang.t("%s via %s", pkg.name, pkg.repo_name) + (pkg.experimental ? " - " + lang.t("Experimental") : ''), value: "AvailableDestinations::" + pkg.code, group: lang.t('Available Destinations') });
									}
		
									callback();
								},
								failed: function () {
									callback();
								}
							});
						}
					});
				};

				$scope.loadDestinations(function () {
					if(!$routeParams.id) return;
					api.getDestination({ 
						data: { _id: $routeParams.id }, 
						success: function(data) {
							$scope.details = data;
							if({}.toString.apply($scope.details.options) !== '[object Object]') {
								$scope.details.options = {};
							}

							$scope.saveData = util.duplicateObject($scope.details);
							$scope.autocomplete.accountText = $scope.saveData.owner_name;
							//delete $scope.details.options;
							$scope.loadDestinationType();
						}
					});
				});
				
				api.getSettings({
					data: { section: 'performance' },
					success: function(data) { 
						$scope.forks = {
							backup: data.backup_forks,
							queueable: data.queueable_forks,
							system: data.system_forks,
							total: data.backup_forks + data.queueable_forks + data.system_forks,
						};
					}
				})

			}]);
});


define('controllers/disasterRecovery',['app'], function(app) {
	app.controller("disasterRecovery",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "confirm", "PermPermissionStore", "lang", "alert",
			function ($rootScope, $scope, $location, $timeout, api, meta, confirm, PermPermissionStore, lang, alert) {

				$scope.disasterRecovery = true;
				$scope.saveing = false;
				$scope.newInstallation = false;
				$scope.loadingMessage = "";

				$scope.saveToDB = function() {
					sessionStorage.disasterRecovery = JSON.stringify({
						details: $scope.details,
						step: $scope.currentStep
					});
				};


				$scope.steps = [
					{
						title: lang.t("What to do next?"),
						description: lang.t("Please select whether to start to recover your server from a disaster, continue with the default JetBackup configuration, or keep current configuration"),
						template: 'disasterRecovery/selection'
					},
					{
						title: lang.t("JB Configurations destination"),
						description: lang.t("Connect to the destination where the JetBackup configuration files are stored"),
						template: 'disasterRecovery/destination'
					},
					{
						title: lang.t("Available JB configuration files"),
						description: lang.t("Select the desired JB configuration file"),
						template: 'disasterRecovery/backups'
					},
					{
						title: lang.t("Adjust Settings"),
						description: lang.t("Adjust the settings"),
						template: 'disasterRecovery/settings'
					},
					{
						title: lang.t("Accounts to recover"),
						description: lang.t("Select the desired accounts you want to restore"),
						template: 'disasterRecovery/accounts'
					}
				];

				if(sessionStorage.disasterRecovery)
				{
					var disasterRecovery = JSON.parse(sessionStorage.disasterRecovery);
					$scope.details = disasterRecovery.details;
					$scope.currentStep = disasterRecovery.step;
				}
				else
				{
					$scope.currentStep = 0;
					$scope.details = {
						destination_id: '',
						drbackups: [],
						drbackup: ''
					};

					$scope.saveToDB();
				}

				$scope.$watch("details", function(){
					$scope.saveToDB();
				}, true);

				$scope.changeStep = function (step) {
					$scope.currentStep = step;
					$scope.saveToDB();
					$scope.currentStepView = $scope.includePath($scope.steps[step].template);
				};


				/*
				$scope.concurrent = 1;
				api.getSettings({section: 'Performance'}, function (response) {
					if(response.success && response.data.concurrentqueueprocesses)
						$scope.concurrent = response.data.concurrentqueueprocesses;
				});

				$scope.updateConcurrentProcess = function(val) {
					if($scope.concurrent + val <= 0) return;
					$scope.concurrent += val;

					var apiParams = {
						section: 'Performance',
						concurrentqueueprocesses: $scope.concurrent
					};

					jetapi.manageSettings(apiParams, function(response) {
						if(!response.success) console.log(response);
					});
				};

				 */

				$scope.changeStep($scope.currentStep);

				$scope.exitDRSure = function (apiCall) {

					if (apiCall === undefined || typeof apiCall !== 'function') apiCall = function (callback) {};

					confirm.open({
						message: lang.t("Are you sure you want to exit disaster recovery mode?"),
						confirm: function () {
							delete sessionStorage.disasterRecovery;

							apiCall(function() {
								window.location = $rootScope.path.location + window.location.search;
							});
						}
					});
				};

				$scope.freshInstallation = function() {
					$scope.exitDRSure(function (callback) {
						if(callback === undefined || typeof callback !== 'function') callback = function() {};

						$scope.newInstallation = true;
						api.factoryReset({
							success: callback,
							failed: function (message) {
								$scope.newInstallation = false;
								alert.error(message);
							}
						});
					});
				};

				$scope.startDR = function() {
					confirm.open({
						message: lang.t("Are you sure you want start disaster recovery? All current data will be lost"),
						confirm: function () {
							$scope.loadingMessage = lang.t("Dropping all JetBackup data from database");
							api.factoryReset({
								data: { drmode: true },
								success: function () { $scope.nextStep(); },
								failed: function (message) { alert.error(message); }
							});
						}
					});
				};

				$scope.exitDR = function() {
					$scope.exitDRSure(function (callback) {
						if(callback === undefined || typeof callback !== 'function') callback = function() {};
						api.exitDisasterRecovery({ 
							success: callback,
							failed: function (message) {
								alert.error(message);
							}
						});
					});
				};

				$scope.nextStep = function() {
					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loadingMessage = '';
					$rootScope.$broadcast("nextStep");
				};

				$scope.startOver = function() {
					if($scope.saveing) return;
					delete sessionStorage.disasterRecovery;
					$scope.changeStep(1);
				};


				$scope.$on('nonrecoverable', function (event, message) {
					$scope.saveing = false;
					alert.error(lang.t("Failed restoring JB Configurations, the DR Wizard will now exit and start over. Error: %s", message));
					$scope.loadingMessage = lang.t("Dropping all JetBackup data from database");

					api.factoryReset({
						data: { drmode: true },
						success: function () {
							$scope.loadingMessage = '';
							$scope.startOver() },
						failed: function (message) { alert.error(message); }
					});
				});

				$scope.$on('error', function (event, message) {
					$scope.saveing = false;
					alert.error(message);
					$scope.loadingMessage = '';
				});

				$scope.$on('loadingMessage', function (event, message) {
					$scope.loadingMessage = message;
				});

				$scope.$on('commitNextStep', function (event, data) {
					for(var i in data) $scope.details[i] = data[i];
					$scope.saveing = false;
					$scope.changeStep($scope.currentStep+1);
					$scope.loadingMessage = '';
				});
			}
		]
	);
});


define('controllers/disasterRecovery/selection',['app'], function(app) {
	app.controller("disasterRecoverySelection",
		["$rootScope", "$scope", "api", function ($rootScope, $scope, api) {
		
			$scope.installed = false;
			
			api.getSettings({
				data: { section: 'general' },
				success: function (data) {
					$scope.installed = data.installed;
				}
			});
		
			$scope.$on('nextStep', function() {
				$scope.$emit("commitNextStep", {});
			});
		}]
	);
});


define('controllers/disasterRecovery/destination',['app'], function(app) {
	app.controller("disasterRecoveryDestination",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "consts", "lang", "util",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, consts, lang, util) {

				$scope.destination_id = '';

				$scope.reindex = function(destination_id, callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function() {};

					api.reindexDestination({ 
						data: { _id: destination_id, backup_type: consts.BACKUP_TYPE_JB_CONFIG }, 
						success: function(data) {
	
							var checkQueueInterval = setInterval(function () {
								api.getQueueGroup({ 
									data: { _id: data._id }, 
									success: function (data) {
										if(data.status < consts.QUEUE_STATUS_COMPLETED) return;
		
										if(checkQueueInterval !== null) clearInterval(checkQueueInterval);
										checkQueueInterval = null;
		
										callback({ 
											success: data.status == consts.QUEUE_STATUS_COMPLETED, 
											message: lang.t("Reindex process finished with %s status", consts.QUEUE_STATUS_NAMES[data.status]) 
										});
									},
									failed: function (message) {

										if(checkQueueInterval !== null) clearInterval(checkQueueInterval);
										checkQueueInterval = null;

										callback({
											success: false,
											message: message
										});
									}
								});
							}, 5000);
						},
						failed: function (message) {
							callback({ success: false, message: message });
						}
					});
				};

				var listBackups = function(contains, success) {
					if(success === undefined) success = function(){};

					api.listBackups({
						data: {
							destination: $scope.destination_id,
							type: consts.BACKUP_TYPE_JB_CONFIG,
							contains:contains,
							sort: { created: -1 }
						},
						success: function (data) {
							success(data);
						},
						failed: function (message) {
							api.deleteDestination({ data: { _id: $scope.destination_id } });
							$scope.$emit("error", message);
						}
					});
				};

				$scope.$on('nextStep', function() {

					$scope.$emit("loadingMessage", lang.t("Creating destination and reindexing JB configurations backups..."));

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function(key) {
						return ($scope.details._id === undefined && key === 'type');
					});

					apiParams.name = "DR destination " + (new Date()).getTime();
					apiParams.readonly = true;
					apiParams.no_reindex = true;
					apiParams.action = 'create';

					api.manageDestination({ 
						data: apiParams, 
						success: function(data) {

							$scope.destination_id = data._id;
	
							$scope.reindex($scope.destination_id, function (response) {
								if(!response.success) {
									api.deleteDestination({ data: { _id: $scope.destination_id } });
									$scope.$emit("error", response.message);
									return;
								}

								listBackups(consts.BACKUP_TYPE_JB_CONFIG_FULL, function (data) {
									var backups = data.backups;
									listBackups((consts.BACKUP_TYPE_JB_CONFIG_FULL^consts.BACKUP_TYPE_JB_CONFIG_WIREDTIGER), function (data) {
										for(var i = 0; i < data.backups.length; i++) backups.push(data.backups[i]);

										if(!backups.length) {
											api.deleteDestination({ data: { _id: $scope.destination_id } });
											$scope.$emit("error", lang.t("No JetBackup 5 configuration files found on this destination. Please verify the Destination Path is set to a directory that includes JetBackup 5 Configuration Backups."));
											return;
										}

										$scope.$emit("commitNextStep", {
											destination_id: $scope.destination_id,
											drbackups: backups,
											drbackup: backups[0]._id
										});
									});
								});
							});
						},
						failed: function (message) {
							$scope.$emit("error", message);
						}
					});
				});

			}
		]
	);
});


define('controllers/disasterRecovery/settings',['app'], function(app) {
	app.controller("disasterRecoverySettings",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "consts", "lang", "util",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, consts, lang, util) {

				$scope.saveData = {
					general: {},
					performance: {},
					resource: {},
					options: {}
				};

				$scope.validateOptions = {};
				$scope.settingsSection = '';
				
				api.getSettings({
					data: { section: 'general' },
					success: function (data) {
						$scope.saveData.general = data;
						$scope.general = util.duplicateObject($scope.saveData.general);
					}
				});

				api.getSettings({
					data: { section: 'performance' },
					success: function (data) {
						$scope.saveData.performance = data;
						$scope.performance = util.duplicateObject($scope.saveData.performance);
					}
				});

				api.getSettings({
					data: { section: 'resource' },
					success: function (data) {
						$scope.saveData.resource = data;
						$scope.resource = util.duplicateObject($scope.saveData.resource);
					}
				});

				api.getSettings({
					data: { section: 'panel' },
					success: function (data) {
						$scope.saveData.options = data.options;
						$scope.panel = util.duplicateObject($scope.saveData.options);
					}
				});

				$scope.$on('validateOptions', function (e, data) {
					$scope.validateOptions = data;
				});

				app.registerController(
					'panelSettings',
					'plugins/panel',
					function(path) {
						$scope.settingsSection = $scope.includePath('panel/view', 'plugins');
					}
				);
				
				$scope.$on('nextStep', function() {

					$scope.$emit("loadingMessage", lang.t("Adjusting settings..."));

					for (var key in $scope.saveData.options) {
						if($scope.validateOptions[key] === undefined) continue;

						if(!$scope.validateOptions[key].validation($scope.saveData.options[key])) {
							$scope.$emit("error", lang.t("Invalid value provided for %s", $scope.validateOptions[key].name));
							return;
						}
					}

					var general = util.saveParams($scope.saveData.general, $scope.general);
					general.section = 'general';
					
					var performance = util.saveParams($scope.saveData.performance, $scope.performance);
					performance.section = 'performance';

					var resource = util.saveParams($scope.saveData.resource, $scope.resource);
					resource.section = 'resource';

					var panel = util.saveParams($scope.saveData.options, $scope.panel);

					api.manageSettings({
						data: general,
						success: function () {

							api.manageSettings({
								data: performance,
								success: function () {

									api.manageSettings({
										data: resource,
										success: function () {

											api.manageSettings({
												data: { section: 'panel', options: panel },
												success: function () {
													$scope.$emit("commitNextStep", {});
												},
												failed: function (message) {
													$scope.$emit("error", message);
												}
											});

										},
										failed: function (message) {
											$scope.$emit("error", message);
										}
									});

								},
								failed: function (message) {
									$scope.$emit("error", message);
								}
							});

						},
						failed: function (message) {
							$scope.$emit("error", message);
						}
					});
				});

			}
		]
	);
});


define('controllers/disasterRecovery/backups',['app'], function(app) {
	app.controller("disasterRecoveryBackups",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, consts, lang, popup) {

				$scope.restore = function(_id, encryption_key) {

					$scope.$emit("loadingMessage", lang.t("Restoring selected JB configurations backup..."));

					var args = { type: consts.QUEUE_ITEM_TYPE_RESTORE, items: [_id] };
					if(encryption_key !== undefined) args.encryption_key = encryption_key;

					api.addQueueItems({ 
						data: args, 
						success: function(data) {

							$scope.failedCounter = 0;
							var checkQueueInterval = setInterval(function () {
								api.getQueueGroup({ 
									data: { _id: data._id }, 
									success: function (data) {

										var group_status = parseInt(data.status);
										if(group_status < consts.QUEUE_STATUS_COMPLETED) {
											if(group_status > consts.QUEUE_STATUS_PROCESSING) $scope.$emit("loadingMessage", consts.QUEUE_STATUS_SUB_NAMES[data.type][group_status]);
											return;
										}
		
										if(checkQueueInterval !== null) clearInterval(checkQueueInterval);
										checkQueueInterval = null;
										
										if(group_status === consts.QUEUE_STATUS_COMPLETED) {
											var params = {};
											if(encryption_key !== undefined) params.private_key = encryption_key;
											$scope.$emit("commitNextStep", params);
											return;
										}
		
										api.listQueueItems({ 
											data: { group_id: data._id }, 
											success: function (data) {
												var message = '';
												if(data.items[0] === undefined) message = lang.t("Restore process finished with %s status", consts.QUEUE_STATUS_NAMES[group_status]);
												else message = data.items[0].message;

												if(data.items[0].data.nonrecoverable)
													$scope.$emit("nonrecoverable", message);
												else
													$scope.$emit("error", message);
											},
											failed: function (message) {
												$scope.$emit("error", message);
											}
										});
									},
									failed: function (message) {
										if(($scope.failedCounter++ < 10)) return;

										if(checkQueueInterval !== null) clearInterval(checkQueueInterval);
										checkQueueInterval = null;

										$scope.$emit("error", message);
									}
								});
							}, 5000);
						},
						failed: function (message) {
							$scope.$emit("error", message);
						}
					});
				};

				$scope.$on('nextStep', function() {

					var backup = { _id: $scope.details.drbackup };

					for(var i = 0; i < $scope.details.drbackups.length; i++) {
						if(backup._id === $scope.details.drbackups[i]._id) {
							backup = $scope.details.drbackups[i];
							break;
						}
					}

					if(backup.encrypted) {

						$scope.privateKeyUIB = popup.open({
							template: 'encryptionKeySelection',
							noController: true,
							scope: $scope
						});

						$scope.privateKeyUIB.result.then(function(encryption_key) {

							if(!encryption_key) {
								$scope.$emit("error", lang.t("You must provide root master key"));
								return;
							}

							$scope.restore(backup._id, encryption_key);
						}, function() {
							$scope.$emit("error", lang.t("You must provide root master key"));
						});

					} else {
						$scope.restore(backup._id);
					}

				});
	}]);
});


define('controllers/disasterRecovery/accounts',['app'], function(app) {
	app.controller("disasterRecoveryAccounts",
		["$rootScope", "$scope",
			function ($rootScope, $scope) {
				$scope.drMode = true;
	}]);
});


define('controllers/restoreConditions',['app'], function(app) {
	app.controller("restoreConditions",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "$q", "api", "meta", "confirm", "alert", "lang",
			function ($rootScope, $scope, $location, $timeout, $interval, $q, api, meta, confirm, alert, lang) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.conditions = [];
				$scope.loadingConditions = false;
				$scope.loaders = {
					state: false,
					delete: false
				};

				meta = meta.new("restore_conditions");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("title");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["title", "content", "type"]);
				meta.setTotalItems($scope.conditions.length);

				$scope.toggleState = function(condition) {
					api.manageRestoreCondition({
						data: { action: 'modify', _id: condition._id, disabled: !condition.disabled },
						success: function(data, message) {
							$scope.loaders.state = false;
							condition.disabled = data.disabled;
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});

					$scope.loaders.state = true;
				};

				$scope.onClickDelete = function(condition) {

					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This restore condition will be permanently deleted!"),
						confirm: function () {
							api.deleteRestoreCondition({ 
								data: { _id: condition._id }, 
								success: function(data, message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function(message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.loaders.delete = false;
							$scope.saveing = false;
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingConditions = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.conditions = [];

					api.listRestoreConditions({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.conditions);
							$scope.conditions = data.conditions;
							$scope.loadingConditions = false;
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/restoreConditionManage',['app'], function(app) {
	app.controller("restoreConditionManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "util", "confirm", "lang", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, util, confirm, lang, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.details = {};
				$scope.saveData = {
					condition: ''
				};

				$scope.saveing = false;
				$scope.changed = false;
				$scope.cancelled = false;


				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/restoreConditions');
				};

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageRestoreCondition({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = response.data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/restoreConditionManage/' + data._id);
							else $location.path('/restoreConditions');
							alert.success(message);
						},
						failed: function(message) {
							$scope.saveing = false;
							alert.error(message);
						},
					});
				};

				$scope.fetch = function() {
					api.getRestoreCondition({ 
						data: { _id: $routeParams.id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});

				};

				if($routeParams.id) $timeout($scope.fetch());
			}
		]
	);

});


define('controllers/backupJobs',['app'], function(app) {
	app.controller("backupJobs",
		["$rootScope", "$scope", "$location", "$timeout", "$sce", "$interval", "$q", "api", "meta", "lang", "filter", "consts", "confirm", "alert",
			function ($rootScope, $scope, $location, $timeout, $sce, $interval, $q, api, meta, lang, filter, consts, confirm, alert) {
				$rootScope.$emit('menuItem', 'BackupJobs');

				$scope.jobs = [];
				$scope.checkingJob = {};
				$scope.loadingJobs = false;
				$scope.filters = {};
				$scope.destinations = undefined;
				$scope.running = {};
				$scope.checkRunningInterval = null;
				$scope.run_now = false;

				$scope.currentTime = parseInt(Date.now() / 1000);
				$interval(function () { $scope.currentTime = parseInt(Date.now() / 1000); }, 100);

				$scope.loaders = {
					state: false,
					quota: false,
					runnow: false,
					duplicate: false,
					delete: false
				};

				meta = meta.new("backup_jobs");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","owner","retain","last_run","disabled"]);
				meta.setTotalItems($scope.jobs.length);

				$scope.viewLogs = function(job) {
					var logsFilter = filter.new("logs_filter");
					logsFilter.setFilter(consts.LOG_TYPE_BACKUP);

					var logsSubFilter = filter.new("logs_subfilter");
					logsSubFilter.setFilter(job._id);

					$scope.changeView('/logs');
				};

				$scope.duplicate = function(job) {

					confirm.open({
						message: lang.t("This backup job will be duplicated!"),
						confirm: function () {
							$scope.loaders.duplicate = true;

							api.duplicateBackupJob({ 
								data: { _id: job._id }, 
								success: function (data, message) {
									$scope.loaders.duplicate = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.duplicate = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};

				$scope.toggleState = function(job) {
					$scope.loaders.state = true;
					var newState = !job.disabled;
					api.manageBackupJob({ 
						data: { action: 'modify', _id: job._id, disabled: newState }, 
						success: function(data) {
							$scope.loaders.state = false;
							job.disabled = data.disabled;
							job.next_run = data.next_run;
						},
						failed: function (message) {
							$scope.loaders.state = false;
							alert.error(message);
						}
					});
				};

				$scope.runBackupJobManually = function(job) {

					if($scope.loaders.runnow) return;
					$scope.loaders.runnow = true;

					api.runBackupJobManually({ 
						data: { _id: job._id }, 
						success: function (data, message) {
							$scope.loaders.runnow = false;
							for(var key in data) job[key] = data[key];
							$scope.running[job._id] = job;
							alert.success(message);
						},
						failed: function (message) {
							$scope.loaders.runnow = false;
							alert.error(message);
						}
					});
				};

				$scope.onClickDelete = function(job) {

					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This backup job will be permanently deleted!"),
						confirm: function () {

							api.deleteBackupJob({ 
								data: { _id: job._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				api.listAccountFilters({ 
					success: function (data) {
						for(var i = 0; i < data.filters.length; i++) {
							$scope.filters[data.filters[i].group_id] = data.filters[i].name;
						}
					}
				});

				$scope.createBackupJob = function() {
					$scope.destinationsCheck(function () {
						$scope.changeView('/backupJobManage');
					});
				};
				
				$scope.destinationsCheck = function (callback) {
					if(callback === undefined) callback = function () {};

					if($scope.destinations !== undefined) {

						if(!$scope.destinations) {
							alert.error(lang.t("You must first create a destination before creating a backup job for this server"));
							return;
						}

						callback();
						return;
					}

					$scope.destinations = false;

					api.listDestinations({ 
						data: { readonly:0 }, 
						success: function(data) {
							$scope.destinations = !!data.destinations.length;
							if(!$scope.destinations) {
								alert.error(lang.t("You must first create a destination before creating a backup job for this server"));
								return;
							}
	
							callback();
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.checkRunning = function() {
					for(var id in $scope.running) {
						api.getBackupJob({ 
							data: { _id: id }, 
							success: function (data) {
								if(data.running) return;
								for(var key in data) $scope.running[id][key] = data[key];
								delete $scope.running[id];
							}
						});
					}
				};

				$scope.$on('$destroy', function() {
					if($scope.checkRunningInterval === null) return;
					clearInterval($scope.checkRunningInterval);
					$scope.checkRunningInterval = null;
				});

				$scope.fetch = function(callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function() {};

					$scope.loadingJobs = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.jobs = [];
					$scope.running = {};

					api.listBackupJobs({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.jobs);
							$scope.jobs = data.jobs;
	
							for(var i = 0; i < $scope.jobs.length; i++) {
	
								var job = $scope.jobs[i];
								var type = parseInt(job.type);
								var contains = parseInt(job.contains);
								var names = [];
	
	
								switch(type) {
									case consts.BACKUP_TYPE_ACCOUNT:
										if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
										else {
											if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
											if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
										}
									break;
									case consts.BACKUP_TYPE_DIRECTORY:
										names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
									break;
									case consts.BACKUP_TYPE_JB_CONFIG:
										names.push(consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_FULL]);
										break;
									case consts.BACKUP_TYPE_DR:
										names.push(consts.BACKUP_TYPE_DR_NAMES[consts.BACKUP_TYPE_DR_FULL]);
									break;
								}
	
								job.contains_name = names.join(', ');
	
								job.filters_sorted = [];
								if(job.filters !== undefined) {
									for(var j = 0; j < job.filters.length; j++) {
										for(var a = 0; a < job.filters[j].length; a++) {
											job.filters_sorted.push(job.filters[j][a]);
										}
									}
								}
	
								if(job.running) $scope.running[job._id] = job;
	
								var destinations_list = [];
								job.destinations = '';
	
								for(var k = 0; k < job.destination_details.length; k++) 
									destinations_list.push(job.destination_details[k].name + (job.destination_details[k].disabled ? " <span style=\"color: #cc0000; font-size: 11px;\">(" + lang.t("Disabled") + ")</span>" : ''));
	
								job.destinations = $sce.trustAsHtml(destinations_list.join(", "));
								//job.next_run_int = job.next_run ? parseInt((new Date(job.next_run)).getTime() / 1000) : 0;
							}
	
							$scope.loadingJobs = false;
							callback();
						}
					});
				};

				$timeout(function () {
					$scope.fetch(function () {
						$scope.checkRunningInterval = setInterval($scope.checkRunning, 3000);
					});
				});
			}
		]
	);
});


define('controllers/backupJobManage',['app'], function(app) {
	app.controller("backupJobManage",
		["$rootScope", "$scope", "$routeParams", "$templateCache", "$route", "$location", "$timeout", "$q", "api", "meta", "util", "lang", "alert", "permissions", "consts", "filterManager", "confirm", "popup",
			function ($rootScope, $scope, $routeParams, $templateCache, $route, $location, $timeout, $q, api, meta, util, lang, alert, permissions, consts, filterManager, confirm, popup) {
				$rootScope.$emit('menuItem', 'BackupJobs');


				$scope.saveData = {
					name: '',
					destination: [],
					owner: $scope.loggedAccount._id,
					owner_name: $scope.loggedAccount.username,
					type: consts.BACKUP_TYPE_ACCOUNT,
					contains: consts.BACKUP_TYPE_ACCOUNT_FULL,
					mysql_exclude_db_by_size: 0,
					postgresql_exclude_db_by_size: 0,
					mongodb_exclude_db_by_size: 0,
					encrypted: 0,
					retry_failed: 0,
					//options: 0,
					structure: consts.BACKUP_STRUCTURE_INCREMENTAL,
					time_parsed: '12:00 AM',
					time: 0,
					monitor: {ranfor:0,notran:0},
					schedules: [],
					filters: [],
					include_list: [],
					exclude_list: []
				};

				$scope.autocomplete = { accountText: $scope.saveData.owner_name };

				$scope.details = {};
				$scope.destinations = {};
				$scope.schedules = {};
				$scope.filters = {};
				$scope.backup_job_names = {};
				$scope.clone_job_names = {};
				$scope.cancelled = false;
				$scope.excluderow = '';
				$scope.includerow = '';
				$scope.type_description = lang.t("Backup the account data that you choose - Files, Emails, Databases, Cron Jobs, Domains, SSL & Panel Configs (If relevant)");
				$scope.type_experimental = '';

				$scope.structures = [
					{ label: consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_INCREMENTAL], value: consts.BACKUP_STRUCTURE_INCREMENTAL },
					{ label: consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_ARCHIVED], value: consts.BACKUP_STRUCTURE_ARCHIVED },
					{ label: consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_COMPRESSED], value: consts.BACKUP_STRUCTURE_COMPRESSED }
				];

				$scope.types = [
					{ label: consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_ACCOUNT], value: consts.BACKUP_TYPE_ACCOUNT }
				];
				
				if(permissions.isRoot) {
					$scope.types.push({ label: consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_DIRECTORY], value: consts.BACKUP_TYPE_DIRECTORY });
					$scope.types.push({ label: consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_DR], value: consts.BACKUP_TYPE_DR });
				}

				$scope.account_types = [
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG], value: consts.BACKUP_TYPE_ACCOUNT_CONFIG },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR], value: consts.BACKUP_TYPE_ACCOUNT_HOMEDIR },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES], value: consts.BACKUP_TYPE_ACCOUNT_DATABASES },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS], value: consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS], value: consts.BACKUP_TYPE_ACCOUNT_EMAILS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FTP], value: consts.BACKUP_TYPE_ACCOUNT_FTP },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS], value: consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS], value: consts.BACKUP_TYPE_ACCOUNT_DOMAINS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES], value: consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES }
				];

				$scope.filtersConditions = [
					{_id:1,name:lang.t("OR")},
					{_id:2,name:lang.t("AND")}
				];
				$scope.filtersStructure = [];

				$scope.$watch("saveData.structure", function () {
					if($scope.saveData.structure == consts.BACKUP_STRUCTURE_ARCHIVED || $scope.saveData.structure == consts.BACKUP_STRUCTURE_COMPRESSED) return;
					$scope.saveData.encrypted = 0;
				});

				$scope.$watch("filtersStructure", function(){
					$scope.buildFilters(true);
				}, true);

				$scope.addRecommendedExcludes = function(list) {
					if(consts.RECOMMENDED_EXCLUDES_ACCOUNT[list] === undefined) return;
					var defaults = consts.RECOMMENDED_EXCLUDES_ACCOUNT[list];
					
					for(var i = 0; i < defaults.length; i++) {
						var exclude = defaults[i];
						if ($scope.saveData.exclude_list.indexOf(exclude) < 0) $scope.saveData.exclude_list.push(exclude);
					}
				};
				
				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.saveData.owner = account._id;
					$scope.saveData.owner_name = account.username;
					$scope.autocomplete.accountText = account.username;
					var activeElement = document.activeElement;
					if (activeElement) activeElement.blur();
				};

				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.buildFilters = function(revert) {
					if(revert === undefined) revert = false;
					if(revert) $scope.saveData.filters = filterManager.buildFilters($scope.filtersStructure);
					else if($scope.saveData.filters !== undefined) $scope.filtersStructure = filterManager.reBuildStructure($scope.saveData.filters);
				};

				$scope.removeFilter = function(index) {
					$scope.filtersStructure = filterManager.removeFilter($scope.filtersStructure, index);
				};

				$scope.upFilter = function(index) {
					if(index === 0) return;

					var clickedValue = $scope.filtersStructure[index];
					var upValue = $scope.filtersStructure[index-1];

					if(index === 1) {
						upValue.cond = clickedValue.cond;
						delete clickedValue.cond;
					}

					$scope.filtersStructure[index] = upValue;
					$scope.filtersStructure[index-1] = clickedValue;
				};

				$scope.downFilter = function(index) {
					if(index === ($scope.filtersStructure.length-1)) return;

					var clickedValue = $scope.filtersStructure[index];
					var downValue = $scope.filtersStructure[index+1];

					if(index === 0) {
						clickedValue.cond = downValue.cond;
						delete downValue.cond;
					}

					$scope.filtersStructure[index] = downValue;
					$scope.filtersStructure[index+1] = clickedValue;
				};

				$scope.fileBrowse = function() {

					popup.open({
						size: "lg",
						template: 'fileBrowse',
						scope: $scope,
						resolve: {
							listPaths: function () { return $scope.saveData.include_list; }
						}
					}).result.then(function(paths) {
						$scope.saveData.include_list = paths;
					}, function() {});
				};

				$scope.filterSelection = function () {

					popup.open({
						size: "lg",
						template: 'accountFilterGroupSelection',
						scope: $scope,
						resolve: {
							filters: function() { return $scope.filters; } ,
							details: function() { return $scope.details; }
						}
					}).result.then(function(filter_id) {

						if(!filter_id) return;
						var data = { _id: filter_id };
						if($scope.filtersStructure.length > 0) data.cond = 1;
						$scope.filtersStructure.push(data);

					}, function () {});
				};

				$scope.manageDestination = function() {

					popup.open({
						template: 'destinationsSelection',
						scope: $scope,
						resolve: {
							destinations: function() { return $scope.saveData.destination; },
							readonly: function () { return false; },
							types: function () { return consts.DESTINATION_JOB_TYPE_BACKUP; },
							legacy: function () { return consts.BACKUP_ALLOW_LEGACY_DESTINATION[$scope.saveData.type]; },
							local: function () { return consts.BACKUP_ALLOW_LOCAL_DESTINATION[$scope.saveData.type]; },
							timebased: function () { return consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[$scope.saveData.type]; }
						}
					}).result.then(function(selected) {
						$scope.saveData.destination = selected;
					}, function () {});

				};

				$scope.databasesExcludes = function() {

					popup.open({
						size: "lg",
						template: 'modifyDatabasesExcludes',
						scope: $scope,
						resolve: {
							db_excludes: function() {
								return {
									mysql_exclude_db_by_size: $scope.saveData.mysql_exclude_db_by_size,
									postgresql_exclude_db_by_size: $scope.saveData.postgresql_exclude_db_by_size,
									mongodb_exclude_db_by_size: $scope.saveData.mongodb_exclude_db_by_size
								}
							}
						}
					}).result.then(function(response) {
						$scope.saveData.mysql_exclude_db_by_size = response.mysql_exclude_db_by_size;
						$scope.saveData.postgresql_exclude_db_by_size = response.postgresql_exclude_db_by_size;
						$scope.saveData.mongodb_exclude_db_by_size = response.mongodb_exclude_db_by_size;
					}, function () {});

				};

				$scope.scheduleSelection = function (schedule) {
					
					popup.open({
						size: "lg",
						template: 'scheduleSelection',
						scope: $scope,
						resolve: {
							schedules: function() { return $scope.schedules; } ,
							schedule: function() { return schedule; },
							details: function() { return $scope.saveData; },
							retain: function () { return true; }
						}
					}).result.then(function(scheduleDetails) {

						if(!scheduleDetails._id || scheduleDetails.retain <= 0) {
							alert.error(lang.t("No schedule and/or backups retain selected"));
							return;
						}

						scheduleDetails.display = $scope.scheduleDisplay(scheduleDetails);

						$scope.schedules[scheduleDetails._id] = scheduleDetails;

						
						if(schedule !== undefined) {
							for(var i in scheduleDetails) {
								if(schedule[i] !== undefined) schedule[i] = scheduleDetails[i];
							}
						} else {
							$scope.saveData.schedules.push({
								_id: scheduleDetails._id,
								name: scheduleDetails.name,
								retain: scheduleDetails.retain,
								next_run: 0
							});
						}
						
						$scope.checkScheduleTimeMismatch();

					}, function () {});
				};

				$scope.checkScheduleTimeMismatch = function () {
					var time = 0;

					for(var i = 0; i < $scope.saveData.schedules.length; i++)
					{
						if($scope.schedules[$scope.saveData.schedules[i]._id] === undefined) return;
						var currentSchedule = $scope.schedules[$scope.saveData.schedules[i]._id];
						if([1,2,3,4].indexOf(currentSchedule.type) < 0) continue;

						if(currentSchedule.type === 1)
						{
							// TODO validate hourly times
							continue;
						}

						if(!time) time = currentSchedule.time;

						if(currentSchedule.time !== time)
						{
							$scope.scheduleTimeMismatch = true;
							return;
						}
					}

					$scope.scheduleTimeMismatch = false;
				};

				$scope.removeSchedule = function (schedule) {

					confirm.open({
						message: lang.t("Are you sure you want to remove this schedule from this job? Please note that all snapshots assigned to this schedule will be deleted in the next job run."),
						confirm: function () {
							for(var i = 0; i < $scope.saveData.schedules.length; i++) {
								if(schedule._id === $scope.saveData.schedules[i]._id) {
									$scope.saveData.schedules.splice(i, 1);
									$scope.checkScheduleTimeMismatch();
									break;
								}
							}

							alert.success("Schedule removed successfully");
						}
					});
				};

				$scope.timeToStr = function(time) {

					time = parseInt(time);

					var ampm = 'AM';
					if(time >= 1200) {
						ampm = 'PM';
						time -= 1200;
					}

					time = '' + time;
					if(time.length < 2) time = '0' + time;

					var minute = time.substr(-2);
					var hour = time.length > 2 ? time.substr(0, time.length-2) : 12;
					if(parseInt(hour) < 10) hour = "0" + parseInt(hour);
					return hour + ":" + minute + " " + ampm;
				};

				$scope.strToTime = function (str) {
					var matches = /^([0-9]+):([0-9]+)\s+(AM+|PM+)$/g.exec(str);
					if(!matches) return 0;
					var output = parseInt(matches[1] + matches[2]);
					if(output >= 1200) output -= 1200;
					if(matches[3] === 'PM') output += 1200;
					return output;
				};

				$scope.validateListPath = function (path, allowPatterns) {
					if(!path.trim()) return false;
					if(allowPatterns) return !consts.PATH_FILTER_PATTERNS.test(path);
					return !consts.PATH_FILTER.test(path);
				};

				$scope.typeChecked = function(type, types) {
					return ( type & types );
				};

				$scope.toggleOptionsTypes = function(option) {
					if($scope.typeChecked(option, $scope.saveData.options)) $scope.saveData.options ^= option;
					else $scope.saveData.options |= option;
				};

				$scope.checkChange = function() {
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				};

				$scope.$watch("saveData", $scope.checkChange, true);
				$scope.$watch("details", $scope.checkChange, true);

				$scope.validateSchedules = function(schedules, callback) {
					if(schedules.length) return callback(true);

					confirm.open({
						message: lang.t("We noticed that you didn't set any schedule for this job. That means that this job will never run automatically, only manually"),
						cancelLabel: lang.t("No, let me set schedules"),
						confirm: function () { callback(true); },
						cancel: function () { callback(false); }
					});
				};

				$scope.fetchSchedules = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};

					api.listSchedules({ 
						success: function(data) {

							for (var i = 0; i < data.schedules.length; i++) {
								var id = data.schedules[i]._id;
								$scope.schedules[id] = data.schedules[i];
								$scope.schedules[id].display = $scope.scheduleDisplay($scope.schedules[id]);
							}

							callback();
						},
						failed: function () {
							callback();
						}
					});
				};

				$scope.fetchFilters = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};

					api.listAccountFilterGroups({ 
						success: function(data) {

							for(var i = 0; i < data.groups.length; i++) {
								$scope.filters[data.groups[i]._id] = data.groups[i];
							}

							callback();
						},
						failed: function () {
							callback();
						}
					});
				};

				$scope.fetchDestinations = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listDestinations({ 
						success: function(data) {
							
							for(var i = 0; i < data.destinations.length; i++) {
								var destination = data.destinations[i];
								destination.display = lang.t("%s destination", destination.type);
								$scope.destinations[destination._id] = destination;
							}
	
							callback();
						}
					});
				};

				$scope.removeDestination = function (destination_id) {

					for(var i = 0; i < $scope.saveData.destination.length; i++) {
						if(destination_id === $scope.saveData.destination[i]) {
							$scope.saveData.destination.splice(i, 1);
							break;
						}
					}
				};

				$scope.updateData = function(details) {
					$scope.details = details;
					$scope.saveData = util.duplicateObject($scope.details);
					$scope.checkScheduleTimeMismatch();
					$scope.buildFilters();
				};

				$scope.toggleBackupType = function(type) {

					switch(type) {
						case consts.BACKUP_TYPE_ACCOUNT:
							$scope.saveData.contains = consts.BACKUP_TYPE_ACCOUNT_FULL;
							$scope.type_description = lang.t("Backup the account data that you choose - Files, Emails, Databases, Cron Jobs, Domains, SSL & Panel Configs (If relevant)");
							$scope.type_experimental = '';
						break;
						case consts.BACKUP_TYPE_DIRECTORY:
							$scope.saveData.contains = consts.BACKUP_TYPE_DIRECTORY_FULL;
							$scope.type_description = lang.t("Backup server files/folders that you choose to include (not necessarily related to accounts).");
							$scope.type_experimental = '';

							if($scope.saveData.include_list === undefined) $scope.saveData.include_list = [];
							if($scope.saveData.exclude_list === undefined) $scope.saveData.exclude_list = [];
						break;
						case consts.BACKUP_TYPE_DR:
							$scope.saveData.contains = consts.BACKUP_TYPE_DR_FULL;
							$scope.type_description = lang.t("Create an entire server backup (BMR) for disaster recovery restore, this will create a bootable ISO to restore from. Note that this works alongside the accounts, so for a full recovery you will need an active all-accounts backup job.");
							$scope.type_experimental = '';
						break;
					}

					var newDestinations = [];
					for(var i = 0; i < $scope.saveData.destination.length; i++) {
						var details = $scope.destinations[$scope.saveData.destination[i]];
						
						if(!consts.BACKUP_ALLOW_LEGACY_DESTINATION[type] && details.legacy) continue;
						if(!consts.BACKUP_ALLOW_LOCAL_DESTINATION[type] && (details.type == 'Local' || details.type == 'Localv2')) continue;
						if(!consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[type] && details.time_based) continue;

						newDestinations.push($scope.saveData.destination[i]);
					}
					$scope.saveData.destination = newDestinations;
				};

				$scope.toggleContains = function(type) {
					if($scope.typeChecked(type, $scope.saveData.contains)) $scope.saveData.contains ^= type;
					else $scope.saveData.contains |= type;
				};

				var checkDuplicateIncludeItems = function(value, list) {
					var withoutTrailing = value.replace(/\/+$/, '');
					var withTrailing = withoutTrailing + '/';
					return (list.indexOf(withoutTrailing) >= 0 || list.indexOf(withTrailing) >= 0);
				};

				$scope.addListRow = function (value, list) {
					if($scope[value] === undefined || !$scope[value].trim()) return;

					if(checkDuplicateIncludeItems($scope[value].trim(), list)){
						alert.error(lang.t('The provided path ("%s") already exists on the list.', $scope[value].trim()));
					}
					else if($scope.validateListPath($scope[value].trim(), value === 'excluderow')) {
						list.push($scope[value].trim());
					}
					else {
						alert.error(lang.t('The provided path ("%s") is invalid. The path must start with a "/"' + (value !== 'excluderow' ? ', also patterns are not allowed.' : '.'), $scope[value].trim() ));
					}

					$scope[value] = '';

				};

				$scope.addMultiListRow = function(type, list) {

					if(type == 'include') {
						$scope.listTitle = lang.t("Directories and Files to include");
						$scope.listData = $scope.saveData.include_list.join("\n");
					} else {
						$scope.listTitle = lang.t("Directories and Files to exclude");
						$scope.listData = $scope.saveData.exclude_list.join("\n");
					}

					$scope.listUIB = popup.open({
						template: 'listSelection',
						noController: true,
						scope: $scope
					});
					
					$scope.listUIB.result.then(function(records) {
						while(list.length) list.pop();
						records = records.split("\n");
						var invalidPaths = [];
						var duplicatePaths = [];
						for(var i = 0; i < records.length; i++) {
							if(type === 'include' && checkDuplicateIncludeItems(records[i], list)) duplicatePaths.push(records[i]);
							else if(!(type === 'include' && records[i] === '/') && $scope.validateListPath(records[i], type === 'exclude')) {
								if (list.indexOf(records[i]) < 0 ) list.push(records[i]);
							}
							else invalidPaths.push(records[i]);
						}

						if(invalidPaths.length) alert.error(lang.t('The following paths ("%s") is invalid. The path must start with a "/" and can\'t have trailing "/"' + (type === 'include' ? ', also patterns are not allowed.' : '.'), invalidPaths.join(", ") ))
						if(duplicatePaths.length) alert.error(lang.t('The provided path(s) ("%s") already exists on the list.', duplicatePaths.join(", ")));
					}, function () {});
				};

				$scope.$on('$destroy', function() {

					if(!$scope.changed || $scope.cancelled) return;

					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirm: $scope.saveChanges,
						cancelLabel: lang.t("Disregard Changes"),
						confirmLabel: lang.t("Save"),
					});
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/backupJobs');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, ['backuptype']);

					if(apiParams.time_parsed) apiParams.time = $scope.strToTime(apiParams.time_parsed);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					$scope.validateSchedules($scope.saveData.schedules, function(isConfirm) {
						if(isConfirm) {
							api.manageBackupJob({ 
								data: apiParams, 
								success: function(data, message) {

									$scope.saveing = false;
									$scope.details = util.duplicateObject($scope.saveData);
									$scope.updateData($scope.details);
	
									if(callback === undefined) {
										if (apply) $location.path('/backupJobManage/' + data._id);
										else $location.path('/backupJobs');
										alert.success(message);
									}

									if(callback !== undefined && typeof callback === 'function') callback();
								},
								failed: function (message) {
									$scope.saveing = false;
									alert.error(message);
									if(callback !== undefined && typeof callback === 'function') callback();
								}
							});
						} else $scope.saveing = false;
					});
				};

				$scope.hideTime = function() {
					if(!$scope.saveData.schedules || !$scope.saveData.schedules.length) return true;
					for(var i=0; i < $scope.saveData.schedules.length; i++) {
						if ($scope.schedules[$scope.saveData.schedules[i]._id].type < 5) return false;
					}
					return true;
				};


				$scope.$on('fetchJobData', function(event, data) {
					$scope.fetchJobData(data._id, data.callback);
				});

				$scope.fetchJobData = function() {
					api.getBackupJob({ 
						data: { _id: $routeParams.id }, 
						success: function(data) {
							$scope.details = data;
							$scope.details.time_parsed = $scope.timeToStr($scope.details.time);
	
							$scope.saveData = util.duplicateObject($scope.details);
							$scope.autocomplete.accountText = $scope.saveData.owner_name;
							$scope.buildFilters();
						}
					});
				};

				$scope.fetchBackupJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listBackupJobs({ 
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.backup_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}
							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.fetchCloneJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listCloneJobs({
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.clone_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}

							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.scheduleDisplay = function(schedule) {

					var list = [];

					switch(schedule.type) {
						case consts.SCHEDULE_TYPE_HOURLY:
							return lang.t("Hourly Schedule runs every %s Hours", schedule.type_data);
						case consts.SCHEDULE_TYPE_DAILY:
							list = schedule.type_data.map(function (value) { return consts.SCHEDULE_WEEK_DAYS_NAMES[value]; });
							return lang.t("Daily Schedule runs every %s", schedule.type_data.length === 7 ? lang.t("day") : list.join(", "));
						case consts.SCHEDULE_TYPE_WEEKLY:
							return lang.t("Weekly Schedule runs every %s", consts.SCHEDULE_WEEK_DAYS_NAMES[schedule.type_data]);
						case consts.SCHEDULE_TYPE_MONTHLY:
							list = schedule.type_data.map(function (value) {
								value = String(value);
								return value + consts.SCHEDULE_TYPE_MONTHLY_SUFFIX[value.substr(value.length-1)];
							});
							return lang.t("Monthly Schedule runs every %s of every month", list.join(", "));
						case consts.SCHEDULE_TYPE_BACKUP_DONE:
							return lang.t("Runs %safter the \"%s\" backup job End", (schedule.delay_amount > 0 ? schedule.delay_amount + ' ' + consts.SCHEDULE_DELAY_TYPE_NAMES[schedule.delay_type] + ' ' : ''), $scope.backup_job_names[schedule.type_data]);
						case consts.SCHEDULE_TYPE_CLONE_DONE:
							return lang.t("Runs %safter the \"%s\" clone job End", (schedule.delay_amount > 0 ? schedule.delay_amount + ' ' + consts.SCHEDULE_DELAY_TYPE_NAMES[schedule.delay_type] + ' ' : ''), $scope.clone_job_names[schedule.type_data]);
					}

				};

				$scope.fetchFilters(function () {
					$scope.fetchBackupJobs(function () {
						$scope.fetchCloneJobs(function () {
							$scope.fetchSchedules(function () {
								$scope.fetchDestinations(function () {
									$scope.fetchJobData();
								});
							});
						});
					});
				});
			}
		]
	);

});


define('controllers/cloneJobs',['app'], function(app) {
	app.controller("cloneJobs",
		["$rootScope", "$scope", "$location", "$timeout", "$sce", "$interval", "$q", "api", "meta", "lang", "filter", "consts", "confirm", "alert",
			function ($rootScope, $scope, $location, $timeout, $sce, $interval, $q, api, meta, lang, filter, consts, confirm, alert) {
				$rootScope.$emit('menuItem', 'CloneJobs');

				$scope.jobs = [];
				$scope.checkingJob = {};
				$scope.loadingJobs = false;
				$scope.filters = {};
				$scope.destinations = undefined;
				$scope.running = {};
				$scope.checkRunningInterval = null;
				$scope.run_now = false;

				$scope.currentTime = parseInt(Date.now() / 1000);
				$interval(function () { $scope.currentTime = parseInt(Date.now() / 1000); }, 100);

				$scope.loaders = {
					state: false,
					quota: false,
					runnow: false,
					duplicate: false,
					delete: false
				};

				meta = meta.new("clone_jobs");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","owner","retain","last_run","disabled"]);
				meta.setTotalItems($scope.jobs.length);

				$scope.viewLogs = function(job) {
					var logsFilter = filter.new("logs_filter");
					logsFilter.setFilter(consts.LOG_TYPE_CLONE);

					var logsSubFilter = filter.new("logs_subfilter");
					logsSubFilter.setFilter(job._id);

					$scope.changeView('/logs');
				};

				$scope.duplicate = function(job) {

					confirm.open({
						message: lang.t("This clone job will be duplicated!"),
						confirm: function () {
							$scope.loaders.duplicate = true;

							api.duplicateCloneJob({ 
								data: { _id: job._id }, 
								success: function (data, message) {
									$scope.loaders.duplicate = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.duplicate = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};

				$scope.toggleState = function(job) {
					$scope.loaders.state = true;
					var newState = !job.disabled;
					api.manageCloneJob({ 
						data: { action: 'modify', _id: job._id, disabled: newState }, 
						success: function(data) {
							$scope.loaders.state = false;
							job.disabled = data.disabled;
							job.next_run = data.next_run;
						},
						failed: function (message) {
							$scope.loaders.state = false;
							alert.error(message);
						}
					});
				};

				$scope.runCloneJobManually = function(job) {

					if($scope.loaders.runnow) return;
					$scope.loaders.runnow = true;

					api.runCloneJobManually({ 
						data: { _id: job._id }, 
						success: function (data, message) {
							$scope.loaders.runnow = false;
							for(var key in data) job[key] = data[key];
							$scope.running[job._id] = job;
							alert.success(message);
						},
						failed: function (message) {
							$scope.loaders.runnow = false;
							alert.error(message);
						}
					});
				};

				$scope.onClickDelete = function(job) {

					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This clone job will be permanently deleted!"),
						confirm: function () {

							api.deleteCloneJob({ 
								data: { _id: job._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				api.listAccountFilters({ 
					success: function (data) {
						for(var i = 0; i < data.filters.length; i++) {
							$scope.filters[data.filters[i].group_id] = data.filters[i].name;
						}
					}
				});

				$scope.createCloneJob = function() {
					$scope.destinationsCheck(function () {
						$scope.changeView('/cloneJobManage');
					});
				};
				
				$scope.destinationsCheck = function (callback) {
					if(callback === undefined) callback = function () {};

					if($scope.destinations !== undefined) {

						if(!$scope.destinations) {
							alert.error(lang.t("You must first create a destination before creating a clone job for this server"));
							return;
						}

						callback();
						return;
					}

					$scope.destinations = false;

					api.listDestinations({ 
						data: { readonly:0 }, 
						success: function(data) {
							$scope.destinations = !!data.destinations.length;
							if(!$scope.destinations) {
								alert.error(lang.t("You must first create a destination before creating a clone job for this server"));
								return;
							}
	
							callback();
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.checkRunning = function() {
					for(var id in $scope.running) {
						api.getCloneJob({ 
							data: { _id: id }, 
							success: function (data) {
								if(data.running) return;
								for(var key in data) $scope.running[id][key] = data[key];
								delete $scope.running[id];
							}
						});
					}
				};

				$scope.$on('$destroy', function() {
					if($scope.checkRunningInterval === null) return;
					clearInterval($scope.checkRunningInterval);
					$scope.checkRunningInterval = null;
				});

				$scope.fetch = function(callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function() {};

					$scope.loadingJobs = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.jobs = [];
					$scope.running = {};

					api.listCloneJobs({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.jobs);
							$scope.jobs = data.jobs;
	
							for(var i = 0; i < $scope.jobs.length; i++) {
	
								var job = $scope.jobs[i];
								var type = parseInt(job.type);
								var contains = parseInt(job.contains);
								var names = [];
	
	
								switch(type) {
									case consts.CLONE_TYPE_ACCOUNT:
										if(contains == consts.CLONE_TYPE_ACCOUNT_FULL) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_FULL]);
										else {
											if(contains & consts.CLONE_TYPE_ACCOUNT_CONFIG) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CONFIG]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_HOMEDIR) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_HOMEDIR]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_DATABASES) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASES]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_EMAILS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_EMAILS]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CRON_JOBS]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_DOMAINS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DOMAINS]);
											if(contains & consts.CLONE_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CERTIFICATES]);
										}
									break;
										/*
									case consts.CLONE_TYPE_DIRECTORY:
										names.push(consts.CLONE_TYPE_DIRECTORY_NAMES[consts.CLONE_TYPE_DIRECTORY_FULL]);
									break;
									
										 */
								}
	
								job.contains_name = names.join(', ');
	
								job.filters_sorted = [];
								if(job.filters !== undefined) {
									for(var j = 0; j < job.filters.length; j++) {
										for(var a = 0; a < job.filters[j].length; a++) {
											job.filters_sorted.push(job.filters[j][a]);
										}
									}
								}
	
								if(job.running) $scope.running[job._id] = job;
	
								var destinations_list = [];
								job.destinations = '';
	
								for(var k = 0; k < job.destination_details.length; k++) 
									destinations_list.push(job.destination_details[k].name + (job.destination_details[k].disabled ? " <span style=\"color: #cc0000; font-size: 11px;\">(" + lang.t("Disabled") + ")</span>" : ''));
	
								job.destinations = $sce.trustAsHtml(destinations_list.join(", "));
								//job.next_run_int = job.next_run ? parseInt((new Date(job.next_run)).getTime() / 1000) : 0;
							}
	
							$scope.loadingJobs = false;
							callback();
						}
					});
				};

				$timeout(function () {
					$scope.fetch(function () {
						$scope.checkRunningInterval = setInterval($scope.checkRunning, 3000);
					});
				});
			}
		]
	);
});


define('controllers/cloneJobManage',['app'], function(app) {
	app.controller("cloneJobManage",
		["$rootScope", "$scope", "$routeParams", "$templateCache", "$route", "$location", "$timeout", "$q", "api", "meta", "util", "lang", "alert", "permissions", "consts", "filterManager", "confirm", "popup",
			function ($rootScope, $scope, $routeParams, $templateCache, $route, $location, $timeout, $q, api, meta, util, lang, alert, permissions, consts, filterManager, confirm, popup) {
				$rootScope.$emit('menuItem', 'cloneJobs');


				$scope.saveData = {
					name: '',
					destination: '',
					owner: $scope.loggedAccount._id,
					owner_name: $scope.loggedAccount.username,
					type: consts.CLONE_TYPE_ACCOUNT,
					contains: consts.CLONE_TYPE_ACCOUNT_FULL,
					//options: 0,
					default_package: '',
					default_owner: '',
					suspend_after: 0,
					time_parsed: '12:00 AM',
					time: 0,
					monitor: {ranfor:0,notran:0},
					schedules: [],
					filters: [],
					include_list: [],
					exclude_list: []
				};

				$scope.autocomplete = { accountText: $scope.saveData.owner_name };

				$scope.details = {};
				$scope.destinations = {};
				$scope.schedules = {};
				$scope.filters = {};
				$scope.backup_job_names = {};
				$scope.clone_job_names = {};
				$scope.cancelled = false;
				$scope.excluderow = '';
				$scope.includerow = '';
				
				$scope.types = [
					{ label: consts.CLONE_TYPE_NAMES[consts.CLONE_TYPE_ACCOUNT], value: consts.CLONE_TYPE_ACCOUNT }
				];

				$scope.account_types = [
					//{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CONFIG], value: consts.CLONE_TYPE_ACCOUNT_CONFIG },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_HOMEDIR], value: consts.CLONE_TYPE_ACCOUNT_HOMEDIR },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASES], value: consts.CLONE_TYPE_ACCOUNT_DATABASES },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASE_USERS], value: consts.CLONE_TYPE_ACCOUNT_DATABASE_USERS },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_EMAILS], value: consts.CLONE_TYPE_ACCOUNT_EMAILS },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_FTP], value: consts.CLONE_TYPE_ACCOUNT_FTP },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CRON_JOBS], value: consts.CLONE_TYPE_ACCOUNT_CRON_JOBS },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DOMAINS], value: consts.CLONE_TYPE_ACCOUNT_DOMAINS },
					{ label: consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CERTIFICATES], value: consts.CLONE_TYPE_ACCOUNT_CERTIFICATES }
				];

				$scope.filtersConditions = [
					{_id:1,name:lang.t("OR")},
					{_id:2,name:lang.t("AND")}
				];

				$scope.filtersStructure = [];

				$scope.$watch("filtersStructure", function(){
					$scope.buildFilters(true);
				}, true);

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.saveData.owner = account._id;
					$scope.saveData.owner_name = account.username;
					$scope.autocomplete.accountText = account.username;
					var activeElement = document.activeElement;
					if (activeElement) activeElement.blur();
				};

				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.buildFilters = function(revert) {
					if(revert === undefined) revert = false;
					if(revert) $scope.saveData.filters = filterManager.buildFilters($scope.filtersStructure);
					else if($scope.saveData.filters !== undefined) $scope.filtersStructure = filterManager.reBuildStructure($scope.saveData.filters);
				};

				$scope.removeFilter = function(index) {
					$scope.filtersStructure = filterManager.removeFilter($scope.filtersStructure, index);
				};

				$scope.upFilter = function(index) {
					if(index === 0) return;

					var clickedValue = $scope.filtersStructure[index];
					var upValue = $scope.filtersStructure[index-1];

					if(index === 1) {
						upValue.cond = clickedValue.cond;
						delete clickedValue.cond;
					}

					$scope.filtersStructure[index] = upValue;
					$scope.filtersStructure[index-1] = clickedValue;
				};

				$scope.downFilter = function(index) {
					if(index === ($scope.filtersStructure.length-1)) return;

					var clickedValue = $scope.filtersStructure[index];
					var downValue = $scope.filtersStructure[index+1];

					if(index === 0) {
						clickedValue.cond = downValue.cond;
						delete downValue.cond;
					}

					$scope.filtersStructure[index] = downValue;
					$scope.filtersStructure[index+1] = clickedValue;
				};

				$scope.fileBrowse = function() {

					popup.open({
						size: "lg",
						template: 'fileBrowse',
						scope: $scope,
						resolve: {
							listPaths: function () { return $scope.saveData.include_list; }
						}
					}).result.then(function(paths) {
						$scope.saveData.include_list = paths;
					}, function() {});
				};

				$scope.filterSelection = function () {

					popup.open({
						size: "lg",
						template: 'accountFilterGroupSelection',
						scope: $scope,
						resolve: {
							filters: function() { return $scope.filters; } ,
							details: function() { return $scope.details; }
						}
					}).result.then(function(filter_id) {

						if(!filter_id) return;
						var data = { _id: filter_id };
						if($scope.filtersStructure.length > 0) data.cond = 1;
						$scope.filtersStructure.push(data);
					}, function () {});
				};

				$scope.manageDestination = function() {

					popup.open({
						template: 'destinationsSelection',
						scope: $scope,
						resolve: {
							destinations: function() { return $scope.saveData.destination; },
							readonly: function () { return false; },
							types: function () { return consts.DESTINATION_JOB_TYPE_CLONE; },
							legacy: function () { return true; },
							local: function () { return true; },
							timebased: function () { return true; }
						}
					}).result.then(function(selected) {
						$scope.saveData.destination = selected;
					}, function () {
						//$log.info('Modal dismissed at: ' + new Date());
					});

				};

				$scope.scheduleSelection = function (schedule) {

					popup.open({
						size: "lg",
						template: 'scheduleSelection',
						scope: $scope,
						resolve: {
							schedules: function() { return $scope.schedules; } ,
							schedule: function() { return schedule; },
							details: function() { return $scope.saveData; },
							retain: function () { return false; }
						}
					}).result.then(function(scheduleDetails) {

						if(!scheduleDetails._id) {
							alert.error(lang.t("No schedule selected"));
							return;
						}

						scheduleDetails.display = $scope.scheduleDisplay(scheduleDetails);

						$scope.schedules[scheduleDetails._id] = scheduleDetails;


						if(schedule !== undefined) {
							for(var i in scheduleDetails) {
								if(schedule[i] !== undefined) schedule[i] = scheduleDetails[i];
							}
						} else {
							$scope.saveData.schedules.push({
								_id: scheduleDetails._id,
								name: scheduleDetails.name,
								retain: scheduleDetails.retain,
								next_run: 0
							});
						}

						$scope.checkScheduleTimeMismatch();

					}, function () {});
				};

				$scope.checkScheduleTimeMismatch = function () {
					var time = 0;

					for(var i = 0; i < $scope.saveData.schedules.length; i++)
					{
						if($scope.schedules[$scope.saveData.schedules[i]._id] === undefined) return;
						var currentSchedule = $scope.schedules[$scope.saveData.schedules[i]._id];
						if([1,2,3,4].indexOf(currentSchedule.type) < 0) continue;

						if(currentSchedule.type === 1)
						{
							// TODO validate hourly times
							continue;
						}

						if(!time) time = currentSchedule.time;

						if(currentSchedule.time !== time)
						{
							$scope.scheduleTimeMismatch = true;
							return;
						}
					}

					$scope.scheduleTimeMismatch = false;
				};

				$scope.removeSchedule = function (schedule) {

					confirm.open({
						message: lang.t("Are you sure you want to remove this schedule from this job? Please note that all snapshots assigned to this schedule will be deleted in the next job run."),
						confirm: function () {
							for(var i = 0; i < $scope.saveData.schedules.length; i++) {
								if(schedule._id === $scope.saveData.schedules[i]._id) {
									$scope.saveData.schedules.splice(i, 1);
									$scope.checkScheduleTimeMismatch();
									break;
								}
							}

							alert.success("Schedule removed successfully");
						}
					});
				};

				$scope.timeToStr = function(time) {

					time = parseInt(time);

					var ampm = 'AM';
					if(time >= 1200) {
						ampm = 'PM';
						time -= 1200;
					}

					time = '' + time;
					if(time.length < 2) time = '0' + time;

					var minute = time.substr(-2);
					var hour = time.length > 2 ? time.substr(0, time.length-2) : 12;
					if(parseInt(hour) < 10) hour = "0" + parseInt(hour);
					return hour + ":" + minute + " " + ampm;
				};

				$scope.strToTime = function (str) {
					var matches = /^([0-9]+):([0-9]+)\s+(AM+|PM+)$/g.exec(str);
					if(!matches) return 0;
					var output = parseInt(matches[1] + matches[2]);
					if(output >= 1200) output -= 1200;
					if(matches[3] === 'PM') output += 1200;
					return output;
				};

				$scope.validateListPath = function (path, allowPatterns) {
					if(!path.trim()) return false;
					if(allowPatterns) return !consts.PATH_FILTER_PATTERNS.test(path);
					return !consts.PATH_FILTER.test(path);
				};

				$scope.typeChecked = function(type, types) {
					return ( type & types );
				};

				$scope.toggleOptionsTypes = function(option) {
					if($scope.typeChecked(option, $scope.saveData.options)) $scope.saveData.options ^= option;
					else $scope.saveData.options |= option;
				};

				$scope.checkChange = function() {
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				};

				$scope.$watch("saveData", $scope.checkChange, true);
				$scope.$watch("details", $scope.checkChange, true);

				$scope.validateSchedules = function(schedules, callback) {
					if(schedules.length) return callback(true);

					confirm.open({
						message: lang.t("We noticed that you didn't set any schedule for this job. That means that this job will never run automatically, only manually"),
						cancelLabel: lang.t("No, let me set schedules"),
						confirm: function () { callback(true); },
						cancel: function () { callback(false); }
					});
				};

				$scope.fetchSchedules = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};

					api.listSchedules({ 
						success: function(data) {

							for (var i = 0; i < data.schedules.length; i++) {
								var id = data.schedules[i]._id;
								$scope.schedules[id] = data.schedules[i];
								$scope.schedules[id].display = $scope.scheduleDisplay($scope.schedules[id]);
							}

							callback();
						},
						failed: function () {
							callback();
						}
					});
				};

				$scope.fetchFilters = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};

					api.listAccountFilterGroups({ 
						success: function(data) {

							for(var i = 0; i < data.groups.length; i++) {
								$scope.filters[data.groups[i]._id] = data.groups[i];
							}

							callback();
						},
						failed: function () {
							callback();
						}
					});
				};

				$scope.fetchDestinations = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listDestinations({ 
						success: function(data) {
							
							for(var i = 0; i < data.destinations.length; i++) {
								var destination = data.destinations[i];
								destination.display = lang.t("%s destination", destination.type);
								$scope.destinations[destination._id] = destination;
							}
	
							callback();
						}
					});
				};

				$scope.removeDestination = function (destination_id) {

					for(var i = 0; i < $scope.saveData.destination.length; i++) {
						if(destination_id === $scope.saveData.destination[i]) {
							$scope.saveData.destination.splice(i, 1);
							break;
						}
					}
				};

				$scope.updateData = function(details) {
					$scope.details = details;
					$scope.saveData = util.duplicateObject($scope.details);
					$scope.checkScheduleTimeMismatch();
					$scope.buildFilters();
				};

				$scope.toggleCloneType = function(type) {

					switch(type) {
						case consts.CLONE_TYPE_ACCOUNT:
							$scope.saveData.contains = consts.CLONE_TYPE_ACCOUNT_FULL;
						break;
						/*
						case consts.BACKUP_TYPE_DIRECTORY:
							$scope.saveData.contains = consts.BACKUP_TYPE_DIRECTORY_FULL;
						break;
						 */
					}
				};

				$scope.toggleContains = function(type) {
					if($scope.typeChecked(type, $scope.saveData.contains)) $scope.saveData.contains ^= type;
					else $scope.saveData.contains |= type;
				};

				var checkDuplicateIncludeItems = function(value, list) {
					var withoutTrailing = value.replace(/\/+$/, '');
					var withTrailing = withoutTrailing + '/';
					return (list.indexOf(withoutTrailing) >= 0 || list.indexOf(withTrailing) >= 0);
				};

				$scope.addListRow = function (value, list) {
					if($scope[value] === undefined || !$scope[value].trim()) return;

					if(checkDuplicateIncludeItems($scope[value].trim(), list)){
						alert.error(lang.t('The provided path ("%s") already exists on the list.', $scope[value].trim()));
					}
					else if($scope.validateListPath($scope[value].trim(), value === 'excluderow')) {
						list.push($scope[value].trim());
					}
					else {
						alert.error(lang.t('The provided path ("%s") is invalid. The path must start with a "/"' + (value !== 'excluderow' ? ', also patterns are not allowed.' : '.'), $scope[value].trim() ));
					}

					$scope[value] = '';

				};

				$scope.addMultiListRow = function(type, list) {

					if(type == 'include') {
						$scope.listTitle = lang.t("Directories and Files to include");
						$scope.listData = $scope.saveData.include_list.join("\n");
					} else {
						$scope.listTitle = lang.t("Directories and Files to exclude");
						$scope.listData = $scope.saveData.exclude_list.join("\n");
					}

					$scope.listUIB = popup.open({
						template: 'listSelection',
						noController: true,
						scope: $scope
					});
					
					$scope.listUIB.result.then(function(records) {
						while(list.length) list.pop();
						records = records.split("\n");
						var invalidPaths = [];
						var duplicatePaths = [];
						for(var i = 0; i < records.length; i++) {
							if(type === 'include' && checkDuplicateIncludeItems(records[i], list)) duplicatePaths.push(records[i]);
							else if($scope.validateListPath(records[i], type === 'exclude')) {
								if (list.indexOf(records[i]) < 0 ) list.push(records[i]);
							}
							else invalidPaths.push(records[i]);
						}

						if(invalidPaths.length) alert.error(lang.t('The following paths ("%s") is invalid. The path must start with a "/" and can\'t have trailing "/"' + (type === 'include' ? ', also patterns are not allowed.' : '.'), invalidPaths.join(", ") ))
						if(duplicatePaths.length) alert.error(lang.t('The provided path(s) ("%s") already exists on the list.', duplicatePaths.join(", ")));
					}, function () {});
				};

				$scope.$on('$destroy', function() {

					if(!$scope.changed || $scope.cancelled) return;

					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirm: $scope.saveChanges,
						cancelLabel: lang.t("Disregard Changes"),
						confirmLabel: lang.t("Save"),
					});
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/cloneJobs');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, ['clonetype']);

					if(apiParams.time_parsed) apiParams.time = $scope.strToTime(apiParams.time_parsed);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					$scope.validateSchedules($scope.saveData.schedules, function(isConfirm) {
						if(isConfirm) {
							api.manageCloneJob({ 
								data: apiParams, 
								success: function(data, message) {

									$scope.saveing = false;
									$scope.details = util.duplicateObject($scope.saveData);
									$scope.updateData($scope.details);
	
									if(callback === undefined) {
										if (apply) $location.path('/cloneJobManage/' + data._id);
										else $location.path('/cloneJobs');
										alert.success(message);
									}

									if(callback !== undefined && typeof callback === 'function') callback();
								},
								failed: function (message) {
									$scope.saveing = false;
									alert.error(message);
									if(callback !== undefined && typeof callback === 'function') callback();
								}
							});
						} else $scope.saveing = false;
					});
				};

				$scope.hideTime = function() {
					if(!$scope.saveData.schedules || !$scope.saveData.schedules.length) return true;
					for(var i=0; i < $scope.saveData.schedules.length; i++) {
						if ($scope.schedules[$scope.saveData.schedules[i]._id].type < 5) return false;
					}
					return true;
				};


				$scope.$on('fetchJobData', function(event, data) {
					$scope.fetchJobData(data._id, data.callback);
				});

				$scope.fetchJobData = function() {
					api.getCloneJob({ 
						data: { _id: $routeParams.id }, 
						success: function(data) {
							$scope.details = data;
							$scope.details.time_parsed = $scope.timeToStr($scope.details.time);
	
							$scope.saveData = util.duplicateObject($scope.details);
							$scope.autocomplete.accountText = $scope.saveData.owner_name;
							$scope.buildFilters();
						}
					});
				};

				$scope.fetchBackupJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listBackupJobs({
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.backup_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}
							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.fetchCloneJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listCloneJobs({
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.clone_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}

							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.scheduleDisplay = function(schedule) {

					var list = [];

					switch(schedule.type) {
						case consts.SCHEDULE_TYPE_HOURLY:
							return lang.t("Hourly Schedule runs every %s Hours", schedule.type_data);
						case consts.SCHEDULE_TYPE_DAILY:
							list = schedule.type_data.map(function (value) { return consts.SCHEDULE_WEEK_DAYS_NAMES[value]; });
							return lang.t("Daily Schedule runs every %s", schedule.type_data.length === 7 ? lang.t("day") : list.join(", "));
						case consts.SCHEDULE_TYPE_WEEKLY:
							return lang.t("Weekly Schedule runs every %s", consts.SCHEDULE_WEEK_DAYS_NAMES[schedule.type_data]);
						case consts.SCHEDULE_TYPE_MONTHLY:
							list = schedule.type_data.map(function (value) {
								value = String(value);
								return value + consts.SCHEDULE_TYPE_MONTHLY_SUFFIX[value.substr(value.length-1)];
							});
							return lang.t("Monthly Schedule runs every %s of every month", list.join(", "));
						case consts.SCHEDULE_TYPE_BACKUP_DONE:
							return lang.t("Runs %safter the \"%s\" backup job End", (schedule.delay_amount > 0 ? schedule.delay_amount + ' ' + consts.SCHEDULE_DELAY_TYPE_NAMES[schedule.delay_type] + ' ' : ''), $scope.backup_job_names[schedule.type_data]);
						case consts.SCHEDULE_TYPE_CLONE_DONE:
							return lang.t("Runs %safter the \"%s\" clone job End", (schedule.delay_amount > 0 ? schedule.delay_amount + ' ' + consts.SCHEDULE_DELAY_TYPE_NAMES[schedule.delay_type] + ' ' : ''), $scope.clone_job_names[schedule.type_data]);
					}

				};

				$scope.fetchFilters(function () {
					$scope.fetchBackupJobs(function () {
						$scope.fetchCloneJobs(function () {
							$scope.fetchSchedules(function () {
								$scope.fetchDestinations(function () {
									$scope.fetchJobData();
								});
							});
						});
					});
				});
			}
		]
	);

});


define('controllers/permissions',['app'], function(app) {
	app.controller("permissions",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "confirm", "util", "permissions", "lang", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, confirm, util, permissions, lang, alert) {
				$rootScope.$emit('menuItem', 'Permissions');

				$scope.saveing = false;
				$scope.changed = false;
				$scope.loading = false;
				$scope.totalFiltered = 0;
				$scope.selectedAccount = '';
				$scope.autocomplete = { accountText: '' };

				$scope.details = {};
				$scope.filtered = {};
				$scope.saveData = {};

				$scope.meta = {
					sectionValue: -1,
					filterType: 1,
					filterValue: ""
				};

				$scope.permissions = {
					canView: false,
					canManage: false
				};

				$scope.types = [
					{ value: 1, label: lang.t('Global Permissions') },
					{ value: 2, label: lang.t('Specific Permissions') }
				];

				$scope.fetch = function() {

					if($scope.meta.filterType === 2 && !$scope.selectedAccount) {
						$scope.details = {};
						$scope.filtered = {};
						$scope.saveData = {};
						$scope.totalFiltered = 0;
						return;
					}

					$scope.loading = true;

					var apiParams = {};
					if($scope.meta.filterType === 2 && $scope.selectedAccount) apiParams.username = $scope.selectedAccount;

					api.getPermissions({ 
						data: apiParams, 
						success: function(data) {
							$scope.details = data.permissions;
							$scope.totalFiltered = 1;
							$scope.saveData = util.duplicateObject($scope.details);
							$scope.filteredList();
							$scope.loading = false;
						}
					});
				};

				$scope.startFetching = function () {
					$scope.details = {};
					$scope.filtered = {};
					$scope.saveData = {};
					$scope.totalFiltered = 0;
					$scope.fetch();
				};

				$scope.resetPermissions = function () {
					confirm.open({
						message:  ($scope.meta.filterType === 2 && $scope.selectedAccount) ? lang.t('Are you sure you want to reset all permissions for the account "%s" to defaults?', $scope.selectedAccount) : lang.t("Are you sure you want to reset all permissions to defaults?"),
						confirm: function () {
							var apiParams = {};
							if($scope.meta.filterType === 2 && $scope.selectedAccount) apiParams.username = $scope.selectedAccount;

							api.resetPermissions({ 
								data: apiParams, 
								success: function(data, message) {
									alert.success(message);
									$scope.startFetching();
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.selectedAccount = account.username;
					//$scope.autocomplete.accountText = account.username;
					$scope.startFetching();
				};

				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};


				$scope.filteredList = function() {

					$scope.filtered = {};
					$scope.totalFiltered = 0;

					if(!$scope.meta.filterValue && $scope.meta.sectionValue === -1) {
						$scope.totalFiltered = 1;
						$scope.filtered = util.duplicateObject($scope.details);
						return;
					}

					for(var i in $scope.details) {
						var details = permissions.get(i);
						if(details === null) continue;

						if(
							($scope.meta.filterValue && !(new RegExp('(' + $scope.meta.filterValue + ')', 'gi')).test(details.name)) ||
							($scope.meta.sectionValue >= 0)
						) continue;

						$scope.totalFiltered++;
						$scope.filtered[i] = $scope.details[i];
					}
				};

				$scope.$on('$destroy', function() {
					if($scope.changed) {
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.startFetching();

				$scope.$watch("autocomplete.accountText", function() {
					if($scope.autocomplete.accountText !== '') return;
					$scope.selectAccount({ username: '' });
				});

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details);
				}, true);

				$scope.saveChanges = function(callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = {
						permissions: util.saveParams($scope.saveData, $scope.details)
					};

					if($scope.meta.filterType === 2 && $scope.selectedAccount) apiParams.username = $scope.selectedAccount;

					api.managePermissions({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.details = util.duplicateObject($scope.saveData);
	
							for(var i in apiParams.permissions) {
								if($scope.filtered[i] !== undefined) $scope.filtered[i] = apiParams.permissions[i];
							}
	
							if(callback !== undefined) callback();
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};
			}]);
});


define('controllers/schedules',['app'], function(app) {
	app.controller("schedules",
		["$rootScope", "$scope", "$location", "$timeout", "api", "lang", "meta", "confirm", "alert", "consts",
			function ($rootScope, $scope, $location, $timeout, api, lang, meta, confirm, alert, consts) {

				$rootScope.$emit('menuItem', 'Schedules');

				$scope.schedules = [];
				$scope.loadingSchedules = false;
				$scope.backup_job_names = {};
				$scope.clone_job_names = {};

				$scope.loaders = {
					delete: false
				};

				meta = meta.new("schedules");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","owner"]);
				meta.setTotalItems($scope.schedules.length);

				$scope.onClickDelete = function(schedule) {

					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This schedule will be permanently deleted!"),
						confirm: function () {

							api.deleteSchedule({
								data: { _id: schedule._id },
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.scheduleDisplay = function(schedule) {

					var list = [];

					switch(schedule.type) {
						case consts.SCHEDULE_TYPE_HOURLY:
							return lang.t("Hourly Schedule runs every %s Hours", schedule.type_data);
						case consts.SCHEDULE_TYPE_DAILY:
							list = schedule.type_data.map(function (value) { return consts.SCHEDULE_WEEK_DAYS_NAMES[value]; });
							return lang.t("Daily Schedule runs every %s", schedule.type_data.length === 7 ? lang.t("day") : list.join(", "));
						case consts.SCHEDULE_TYPE_WEEKLY:
							return lang.t("Weekly Schedule runs every %s", consts.SCHEDULE_WEEK_DAYS_NAMES[schedule.type_data]);
						case consts.SCHEDULE_TYPE_MONTHLY:
							list = schedule.type_data.map(function (value) {
								value = String(value);
								return value + consts.SCHEDULE_TYPE_MONTHLY_SUFFIX[value.substr(value.length-1)];
							});
							return lang.t("Monthly Schedule runs every %s of every month", list.join(", "));
						case consts.SCHEDULE_TYPE_BACKUP_DONE:
							return lang.t("Runs after the \"%s\" backup job Ends", $scope.backup_job_names[schedule.type_data]);
						case consts.SCHEDULE_TYPE_CLONE_DONE:
							return lang.t("Runs after the \"%s\" clone job Ends", $scope.clone_job_names[schedule.type_data]);
					}

				};

				$scope.fetchBackupJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listBackupJobs({
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.backup_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}
							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.fetchCloneJobs = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function() {};
					api.listCloneJobs({
						success: function (data) {
							for(var i = 0; i < data.jobs.length; i++) {
								$scope.clone_job_names[data.jobs[i]._id] = data.jobs[i].name;
							}

							callback();
						},
						failed: function () {
							callback();
						}
					})
				};

				$scope.fetch = function() {

					$scope.loadingSchedules = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.schedules = [];

					api.listSchedules({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.schedules);
							$scope.schedules = data.schedules;
							$scope.loadingSchedules = false;
						}
					});
				};

				$scope.fetchBackupJobs(function () {
					$scope.fetchCloneJobs(function () {
						$scope.fetch();
					});
				});
	}]);
});


define('controllers/scheduleManage',['app'], function(app) {
	app.controller("scheduleManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "meta", "lang", "util", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, meta, lang, util, consts, alert) {
				$rootScope.$emit('menuItem', 'BackupJobs');

				$scope.saveData = {};
				$scope.details = {
					name: '',
					type: 1,
					type_data: '',
					delay_type: 'minutes',
					delay_amount: 0
				};

				$scope.saveing = false;

				$scope.changed = false;
				$scope.cancelled = false;

				$scope.types = [
					//{ label: lang.t('Manually'), value: 8 },
					{ label: lang.t('Hourly'), value: consts.SCHEDULE_TYPE_HOURLY },
					{ label: lang.t('Daily'), value: consts.SCHEDULE_TYPE_DAILY },
					{ label: lang.t('Weekly'), value: consts.SCHEDULE_TYPE_WEEKLY },
					{ label: lang.t('Monthly'), value: consts.SCHEDULE_TYPE_MONTHLY },
					{ label: lang.t('After Backup Job Done'), value: consts.SCHEDULE_TYPE_BACKUP_DONE },
					{ label: lang.t('After Clone Job Done'), value: consts.SCHEDULE_TYPE_CLONE_DONE }
				];

				$scope.hours = [
					{ label: lang.t('Every Hour'), value: 1 },
					{ label: lang.t('Every 2 Hours'), value: 2 },
					{ label: lang.t('Every 3 Hours'), value: 3 },
					{ label: lang.t('Every 4 Hours'), value: 4 },
					{ label: lang.t('Every 6 Hours'), value: 6 },
					{ label: lang.t('Every 8 Hours'), value: 8 },
					{ label: lang.t('Every 12 Hours'), value: 12 }
				];

				$scope.days = [
					{ label: lang.t('Sunday'), value: 1 },
					{ label: lang.t('Monday'), value: 2 },
					{ label: lang.t('Tuesday'), value: 3 },
					{ label: lang.t('Wednesday'), value: 4 },
					{ label: lang.t('Thursday'), value: 5 },
					{ label: lang.t('Friday'), value: 6 },
					{ label: lang.t('Saturday'), value: 7 }
				];

				$scope.months = [
					{ label: lang.t('%sst of the month', 1), value: 1 },
					{ label: lang.t('%sth of the month', 7), value: 7 },
					{ label: lang.t('%sth of the month', 14), value: 14 },
					{ label: lang.t('%sst of the month', 21), value: 21 },
					{ label: lang.t('%sth of the month', 28), value: 28 }
				];

				$scope.delay_types = [
					{ label: lang.t('Minutes'), value: consts.SCHEDULE_DELAY_TYPE_MINUTES },
					{ label: lang.t('Hours'), value: consts.SCHEDULE_DELAY_TYPE_HOURS },
					{ label: lang.t('Days'), value: consts.SCHEDULE_DELAY_TYPE_DAYS }
				];

				$scope.backups = [ { _id: '', name: lang.t("- Select Backup Job -") } ];
				$scope.clones = [ { _id: '', name: lang.t("- Select Clone Job -") } ];

				$scope.toggleTypeData = function(value) {
					var idx = $scope.saveData.type_data.indexOf(value);
					if (idx > -1) $scope.saveData.type_data.splice(idx, 1);
					else $scope.saveData.type_data.push(value);
				};

				$scope.loadScheduleType = function(type, defaults) {

					if($scope.saveData !== undefined) var name = $scope.saveData.name;
					$scope.saveData = util.duplicateObject($scope.details);
					if(name !== undefined) $scope.saveData.name = name;

					if(typeof $scope.details.type_data === 'object')
					{
						$scope.saveData.type_data = [];
						for(var i = 0; i < $scope.details.type_data.length; i++) $scope.saveData.type_data.push($scope.details.type_data[i]);
					}

					$scope.saveData.type = type;

					var mongoIdPattern = new RegExp("^[a-f0-9]{24}$", 'g');

					switch(type)
					{
						case consts.SCHEDULE_TYPE_HOURLY:
							if(defaults) $scope.saveData.type_data = 1;
						break;

						case consts.SCHEDULE_TYPE_DAILY:
						case consts.SCHEDULE_TYPE_MONTHLY:
							if(defaults) $scope.saveData.type_data = [];
						break;

						case consts.SCHEDULE_TYPE_WEEKLY:
							if(defaults) $scope.saveData.type_data = 1;
						break;

						case consts.SCHEDULE_TYPE_BACKUP_DONE:
							if(
								$scope.saveData.type_data === undefined ||
								typeof $scope.saveData.type_data !== 'string' ||
								!mongoIdPattern.test($scope.saveData.type_data.trim())
							) $scope.saveData.type_data = '';

							api.listBackupJobs({ 
								success: function(data) {
									for(var i = 0; i < data.jobs.length; i++) {
										if($scope.excludeids && $scope.excludeids.indexOf(data.jobs[i]._id) >=0) continue;
										$scope.backups.push({
											_id: data.jobs[i]._id,
											name: data.jobs[i].name
										});
									}
								}
							});
						break;

						case consts.SCHEDULE_TYPE_CLONE_DONE:
							if(
								$scope.saveData.type_data === undefined ||
								typeof $scope.saveData.type_data !== 'string' ||
								!mongoIdPattern.test($scope.saveData.type_data.trim())
							) $scope.saveData.type_data = '';

							api.listCloneJobs({
								success: function(data) {
									for(var i = 0; i < data.jobs.length; i++) {
										if($scope.excludeids && $scope.excludeids.indexOf(data.jobs[i]._id) >=0) continue;
										$scope.clones.push({
											_id: data.jobs[i]._id,
											name: data.jobs[i].name
										});
									}
								}
							});
							break;
					}
				};

				$scope.fetchScheduleData = function(schedule_id) {

					api.getSchedule({ 
						data: { _id: schedule_id }, 
						success: function(data) {
							$scope.details = data;
							//$scope.details.time = $scope.details.time_parsed;
							$scope.loadScheduleType($scope.details.type);
						}
					});

				};

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id','checked']);
				}, true);

				$scope.$on('createSchedule', function (event) {
					$scope.saveChanges(true, function(state, data, message) {
						$scope.$emit('scheduleResponse', { success: state, data: data, message: message });
					});
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/schedules');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function (key) {
						if(key === 'type') return true;

						// More validations

						return false;
					});

					//if([2,3,4].indexOf(apiParams.type) >= 0 && typeof apiParams.time === 'string') apiParams.time = $scope.parseTime(apiParams.time);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageSchedule({ 
						data: apiParams, 
						success: function(data, message) {

							$scope.saveing = false;
	
							if(callback !== undefined) {
								callback(true, data, message);
								return;
							}
							
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/scheduleManage/' + data._id);
							else $location.path('/schedules');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;

							if(callback !== undefined) {
								callback(false, {}, message);
								return;
							}

							alert.error(message);
						}
					});
				};

				var schedule_id = $routeParams.id;

				if(schedule_id) $timeout($scope.fetchScheduleData(schedule_id));
				else $scope.loadScheduleType($scope.details.type, true);
	}]);
});


define('controllers/scheduleManagePopup',['app'], function(app) {

	app.controller('scheduleManagePopup',
		["$uibModalInstance", "$routeParams", "$rootScope", "$scope", "api", "lang", "schedule", "excludeids", "alert",
			function($uibModalInstance, $routeParams, $rootScope, $scope, api, lang, schedule, excludeids, alert) {

				$scope.excludeids = excludeids;
				$scope.schedule = schedule;
				
				/*
				$scope.saveData = {
					name: '',
					type: 1,
					typedata: '',
					time: '01:00 AM',
					delaytype: 'minutes',
					delayamount: 0
				};
				*/

				$routeParams.id = null;
				$scope.saveData = {};

				if($scope.schedule) $routeParams.id = $scope.schedule._id;

				$scope.$on('scheduleResponse', function (event, response) {

					if(!response.success) {
						alert.error(response.message);
						return;
					}

					api.getSchedule({ 
						data: { _id: response.data._id }, 
						success: function(data) {
							alert.success(response.message);
							$uibModalInstance.close(data);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				});

				$scope.ok = function () {
					$rootScope.$broadcast('createSchedule');
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss();
				};
	}]);

});


define('controllers/scheduleSelection',['app'], function(app) {
	app.controller('scheduleSelection',
		["$uibModalInstance", "$scope", "lang", "schedules", "schedule", "details", "alert", "retain", "popup",
			function($uibModalInstance, $scope, lang, schedules, schedule, details, alert, retain, popup) {

				$scope.schedule = schedule;
				$scope.schedules = [];
				$scope.allSchedules = schedules;
				$scope.includeRetain = retain;
				$scope.scheduleDetails = { retain: 0 };
				$scope.details = (schedule !== undefined) ? schedule : { _id: '', retain: 0 }

				function checkScheduleId(id) {
					for(var i = 0; i < $scope.schedules.length; i++) if($scope.schedules[i]._id == id) return true;
					return false;
				}

				$scope.newSchedule = function () {
		
					popup.open({
						size: "lg",
						template: 'scheduleManagePopup',
						scope: $scope,
						resolve: {
							schedule: function() { return {}/*schedule*/; },
							excludeids: function() { return []; }
						}
					}).result.then(function(scheduleDetails) {
		
						if(!scheduleDetails._id) {
							alert.error(lang.t("Failed to create schedule"));
							return;
						}
		
						$scope.allSchedules[scheduleDetails._id] = scheduleDetails;
						$scope.calculateUsableSchedules(function () {
							if(!checkScheduleId(scheduleDetails._id)) {
								alert.error(lang.t("You can't use this type of schedule as same schedule type is already assigned to this job"));
								return;
							}
		
							$scope.details._id = scheduleDetails._id;
						});
					}, function () {});
		
				};
				
				$scope.calculateUsableSchedules = function(callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function(){};
		
					$scope.schedules = [];
					$scope.schedulesTypesInUse = [];
		
					for(var i = 0; i < details.schedules.length; i++) {
						if(schedules[details.schedules[i]._id] === undefined) continue;
						$scope.schedulesTypesInUse.push(schedules[details.schedules[i]._id].type);
					}
		
					for(var i in $scope.allSchedules)
					{
						if((schedule === undefined || $scope.allSchedules[schedule._id].type !== $scope.allSchedules[i].type) && $scope.schedulesTypesInUse.indexOf($scope.allSchedules[i].type) >= 0) continue;
		
						var add = true;
		
						for(var a = 0; a < details.schedules.length; a++) {
							if(
								(i === details.schedules[a]._id &&
									(schedule === undefined || schedule._id !== i))
							)
							{
								add = false;
								break;
							}
						}
		
						if(add) {
							$scope.allSchedules[i].label = $scope.allSchedules[i].name + ' (' + $scope.allSchedules[i].type_name + ')';
							$scope.schedules.push($scope.allSchedules[i]);
						}
					}
		
					callback();
				};
		
				$scope.calculateUsableSchedules();
		
				$scope.$watch('details', function() {
					if(!$scope.details._id) {
						if($scope.schedules.length) {
							$scope.scheduleDetails = $scope.schedules[0];
							$scope.details._id = $scope.scheduleDetails._id;
						}
						return;
					}
					
					
					$scope.scheduleDetails = $scope.allSchedules[$scope.details._id];
					$scope.scheduleDetails.retain = $scope.details.retain;
				}, true);
				/*
				if(schedule !== undefined) {
					for(var i in schedule) $scope.scheduleDetails[i] = schedule[i];
				} else {
					if($scope.schedules.length) {
						for(var i in $scope.schedules[0]) $scope.scheduleDetails[i] = $scope.schedules[0][i];
					} else {
						$scope.scheduleDetails = { retain: 0 };
					}
				}
				*/
		
				$scope.ok = function () {
					$scope.scheduleDetails.retain = parseInt($scope.scheduleDetails.retain);
					$uibModalInstance.close( $scope.scheduleDetails );
				};
		
				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
	}]);

});


define('controllers/queue',['app'], function(app) {
	app.controller("queue",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "consts", "lang", "permissions", "confirm", "alert", "popup",
			function ($rootScope, $scope, $location, $timeout, api, meta, consts, lang, permissions, confirm, alert, popup) {
				$rootScope.$emit('menuItem', 'Queue');

				var type = consts.QUEUE_ITEM_TYPE_BACKUP | consts.QUEUE_ITEM_TYPE_CLONE | consts.QUEUE_ITEM_TYPE_REINDEX;
				if(permissions.canRestoreBackups) type |= consts.QUEUE_ITEM_TYPE_RESTORE;
				if(permissions.canDownloadBackups) type |= consts.QUEUE_ITEM_TYPE_DOWNLOAD;
				if(permissions.isRoot) type |= (consts.QUEUE_ITEM_TYPE_SECURITY | consts.QUEUE_ITEM_TYPE_INTEGRITY_CHECK | consts.QUEUE_ITEM_TYPE_SNAPSHOT_DELETE | consts.QUEUE_ITEM_TYPE_EXTENSION_INSTALLATION | consts.QUEUE_ITEM_TYPE_EXTENSION_QUEUE);

				var groupsProcessing = [];
				var groupsById = {};
				$scope.groups = [];
				$scope.loadingGroups = false;
				$scope.stopping = false;
				$scope.destroy = false;
				$scope.filter = type;
				$scope.filterOptions = [
					{ label: lang.t('All Queue Items'), value: type },
					{ label: lang.t('Backup Queue Items'), value: consts.QUEUE_ITEM_TYPE_BACKUP },
					{ label: lang.t('Clone Queue Items'), value: consts.QUEUE_ITEM_TYPE_CLONE }
				];

				if(permissions.canRestoreBackups) $scope.filterOptions.push({ label: lang.t('Restore Queue Items'), value: consts.QUEUE_ITEM_TYPE_RESTORE });
				if(permissions.canDownloadBackups) $scope.filterOptions.push({ label: lang.t('Download Queue Items'), value: consts.QUEUE_ITEM_TYPE_DOWNLOAD });
				if(permissions.isRoot) {
					$scope.filterOptions.push({ label: lang.t('Security Queue Items'), value: consts.QUEUE_ITEM_TYPE_SECURITY });
					$scope.filterOptions.push({ label: lang.t('Integrity Check Queue Items'), value: consts.QUEUE_ITEM_TYPE_INTEGRITY_CHECK });
					$scope.filterOptions.push({ label: lang.t('Snapshot Cleanup Queue Items'), value: consts.QUEUE_ITEM_TYPE_SNAPSHOT_DELETE });
					$scope.filterOptions.push({ label: lang.t('Wordpress Installation'), value: consts.QUEUE_ITEM_TYPE_EXTENSION_INSTALLATION });
					$scope.filterOptions.push({ label: lang.t('Wordpress Mass Deployment'), value: consts.QUEUE_ITEM_TYPE_EXTENSION_QUEUE });
				}

				$scope.filterOptions.push({ label: lang.t('Reindex Queue Items'), value: consts.QUEUE_ITEM_TYPE_REINDEX });

				meta = meta.new("queue");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setTotalItems($scope.groups.length);

				$scope.stopGroup = function(group) {
					if($scope.stopping) return;

					$scope.stopping = true;

					api.stopQueueGroup({ 
						data: { _id: group._id }, 
						success: function (data, message) {
							$scope.stopping = false;
							$scope.fetch();
							alert.success(message);
						},
						failed: function (message) {
							$scope.stopping = false;
							alert.error(message);
						}
					});
				};

				var fetchGroups = function(apiParams, withLoader, callback) {

					if(withLoader === undefined) withLoader = true;
					if(callback === undefined || typeof callback !== 'function') callback = function(){};

					api.listQueueGroups({ 
						data: apiParams,
						withLoader: withLoader,
						success: function(data) {

							var groups = [];
							for(var i = 0; i < data.groups.length; i++) {
								var group = data.groups[i];
								if(parseInt(group.items_completed) <= 0 || parseInt(group.items) <= 0) group.items_progress_percentage = 0
								else group.items_progress_percentage = parseInt((parseInt(group.items_completed) / parseInt(group.items)) * 100);

								if(group.type === consts.QUEUE_ITEM_TYPE_BACKUP) {
									if(group.data.snapshot) {
										group.data = {
											schedule: lang.t("Backup on Demand"),
											account: group.owner_name,
										};
									} else {

										group.data = {
											schedule: group.data.manually ? lang.t("Manually") : lang.t("Backup Job Schedule"),
											"Job Id": group.data._id,
											"Job Name": group.data.name,
										}
									}
								}

								groups.push(group);
							}
	
							callback(groups, data.total);
						},
						failed: function (message) {
							alert.error(message);
							callback([], 0);
						}
					});

				};

				$scope.cancelAll = function() {

					confirm.open({
						message: lang.t("All queue items will be cancelled"),
						confirm: function () {
							api.stopAllQueueGroup({ 
								success: function(data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.viewGroupItems = function(group) {

					popup.open({
						size: "xl",
						template: 'queueItems',
						scope: $scope,
						resolve: {
							group: function() { return group; }
						}
					}).result.then(function() {}, function () {});

				};

				$scope.viewGroupLog = function(group) {

					api.getQueueGroup({ 
						data: { _id: group._id, get_log_contents: 1 }, 
						success: function (data) {

							if(!data.log_contents) {
								alert.error(lang.t("No log content found"));
								return;
							}
	
							popup.open({
								size: "lg",
								template: 'queueLogViewer',
								scope: $scope,
								resolve: {
									group: function() { return data; },
									reload: function() {
										return function(callback) {
											api.getQueueGroup({
												data: { _id: group._id, get_log_contents: 1 },
												success: function (data) {
													if(callback !== undefined) callback(data);
												}
											});
										}
									}
								}
							}).result.then(function() {}, function () {});
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.checkRunningStatusesTimeout = null;

				$scope.rerunFailedItem = function(group) {

					api.rerunFailedQueueGroup({
						data: { _id: group._id },
						success: function (data, message) {
							for(var key in data) group[key] = data[key];
							groupsProcessing.push(group._id);
							$scope.startRunningStatuses();
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};
				
				$scope.clear = function() {

					api.clearQueue({ 
						success: function () {
							$scope.fetch();
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};
				$scope.fetch = function() {

					$scope.loadingGroups = true;

					var apiParams = {
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						type: $scope.filter
					};

					$scope.groups = [];
					fetchGroups(apiParams, true, function(groups, total) {
						meta.setTotalItems(total);
						meta.calculate(groups);
						
						var allGroups = [];
						for(var i = 0; i < groups.length; i++) {
							var group = groups[i];
							if(group.status < consts.QUEUE_STATUS_COMPLETED) groupsProcessing.push(group._id);
							groupsById[group._id] = group;
							allGroups.push(group);
						}
						$scope.groups = allGroups;

						if(groupsProcessing.length > 0) $scope.startRunningStatuses();

						$scope.loadingGroups = false;
					});
				};

				var checkRunningStatuses = function() {
					fetchGroups({ type: $scope.filter }, false, function(groups, total) {
						for(var i = 0; i < groups.length; i++) {
							var group = groups[i];
							var index = groupsProcessing.indexOf(group._id);
							if(index < 0) continue;
							for(var key in groupsById[group._id]) groupsById[group._id][key] = group[key];
							if(group.status >= consts.QUEUE_STATUS_COMPLETED) groupsProcessing.splice(index, 1);
						}

						if(groupsProcessing.length > 0) $scope.startRunningStatuses();
					});
				};

				$scope.clearRunningStatuses = function() {
					if($scope.checkRunningStatusesTimeout !== null) clearTimeout($scope.checkRunningStatusesTimeout);
					$scope.checkRunningStatusesTimeout = null;
				};

				$scope.startRunningStatuses = function() {
					$scope.clearRunningStatuses();
					if($scope.destroy) return;
					$scope.checkRunningStatusesTimeout = setTimeout(checkRunningStatuses, 1000);
				};

				$scope.$on('$destroy', function() {
					$scope.destroy = true;
					$scope.clearRunningStatuses();
				});

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/queueItems',['app'], function(app) {
	app.controller('queueItems',
		["$uibModalInstance", "$scope", "$timeout", "lang", "meta", "api", "consts", "alert", "group", "popup",
			function($uibModalInstance, $scope, $timeout, lang, meta, api, consts, alert, group, popup) {

				var itemsProcessing = [];
				var itemsById = {};
				$scope.group = group;
				$scope.items = [];
				$scope.loadingItems = false;
				$scope.checkRunningStatusesTimeout = null;
				$scope.destroy = false;

				$scope.loaders = {
					view: false
				};

				meta = meta.new("queue_items");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("priority");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["priority","started","ended","execution_time","owner","status"]);
				meta.setTotalItems($scope.items.length);
				meta.setPageSizes([5,10]);
				meta.setPageSize(10);
				meta.setLimit(10);
				
				$scope.viewLogItem = function(item) {
					$scope.loaders.view = true;

					api.getQueueItem({ 
						data: { _id: item._id, get_log_contents: 1 }, 
						success: function (data) {

							$scope.loaders.view = false;
							
							if(!data.content) {
								alert.error(lang.t("No log content found"));
								return;
							}
	
							popup.open({
								size: "lg",
								template: 'logViewer',
								scope: $scope,
								resolve: {
									log: function() { return {
										_id: data._id,
										file: data.file,
										content: data.content,
										start_time: data.started,
										end_time: data.ended,
										execution_time: data.execution_time,
										status: consts.QUEUE_STATUS_TO_LOG[data.status] === undefined ? consts.LOG_STATUS_PROCESSING : consts.QUEUE_STATUS_TO_LOG[data.status],
										information: []
									}; },
									reload: function () {
										return function(callback) {
											api.getQueueItem({
												data: { _id: item._id, get_log_contents: 1 },
												success: function (data) {
													if(callback !== undefined) callback({
														_id: data._id,
														file: data.file,
														content: data.content,
														start_time: data.started,
														end_time: data.ended,
														execution_time: data.execution_time,
														status: consts.QUEUE_STATUS_TO_LOG[data.status] === undefined ? consts.LOG_STATUS_PROCESSING : consts.QUEUE_STATUS_TO_LOG[data.status],
														information: []
													});
												}
											});
										}
									}
								}
							}).result.then(function() {}, function () {});
						},
						failed: function (message) {
							$scope.loaders.view = false;
							alert.error(message);
						}
					});
				};

				var fetchItems = function(apiParams, withLoader, callback) {

					if(withLoader === undefined) withLoader = true;
					if(callback === undefined || typeof callback !== 'function') callback = function(){};

					apiParams.group_id = $scope.group._id;
					
					api.listQueueItems({
						data: apiParams,
						withLoader: withLoader,
						success: function(data) {
							callback(data.items, data.total);
						},
						failed: function (message) {
							alert.error(message);
							callback([], 0);
						}
					});

				};

				var checkRunningStatuses = function() {
					fetchItems({}, false, function(items, total) {
						for(var i = 0; i < items.length; i++) {
							var item = items[i];
							var index = itemsProcessing.indexOf(item._id);
							if(index < 0) continue;
							for(var key in itemsById[item._id]) itemsById[item._id][key] = item[key];
							if(item.status >= consts.QUEUE_STATUS_COMPLETED) itemsProcessing.splice(index, 1);
						}

						if(itemsProcessing.length > 0) $scope.startRunningStatuses();
					});
				};

				$scope.clearRunningStatuses = function() {
					if($scope.checkRunningStatusesTimeout !== null) clearTimeout($scope.checkRunningStatusesTimeout);
					$scope.checkRunningStatusesTimeout = null;
				};

				$scope.startRunningStatuses = function() {
					$scope.clearRunningStatuses();
					if($scope.destroy) return;
					$scope.checkRunningStatusesTimeout = setTimeout(checkRunningStatuses, 1000);
				};

				$scope.fetch = function() {

					$scope.loadingItems = true;

					var apiParams = {
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						sort: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.items = [];
					fetchItems(apiParams, true, function (items, total) {
						meta.setTotalItems(total);
						meta.calculate(items);

						var allItems = [];
						for(var i = 0; i < items.length; i++) {
							var item = items[i];
							if(item.status < consts.QUEUE_STATUS_COMPLETED) itemsProcessing.push(item._id);
							itemsById[item._id] = item;
							allItems.push(item);
						}
						$scope.items = allItems;

						if(itemsProcessing.length > 0) $scope.startRunningStatuses();
						
						$scope.loadingItems = false;
					});
					/*
					
					if(update === undefined) update = false;
					if(callback === undefined || typeof callback !== "function") callback = function(){};

					if($scope.loadingItems) {
						if(update && !$scope.destroied) $scope.timeout = setTimeout(function() { $scope.fetch(true); }, 1000);
						return;
					}
					$scope.updating = update;
					$scope.loadingItems = true;


					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					//$scope.items = [];

					api.listQueueItems({
						withLoader: !update,
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.items);
							
							if(update) {
								
								for(var i = 0; i < data.items.length; i++) {
									var item = data.items[i];
									
									for(var j = 0; j < $scope.items.length; j++) {
										if($scope.items[j]._id !== item._id) continue;
	
										$scope.items[j].priority = item.priority;
										$scope.items[j].started = item.started;
										$scope.items[j].ended = item.ended;
										$scope.items[j].execution_time = item.execution_time;
										$scope.items[j].status = item.status;
										
										break;
									}
								}
								
								if(!$scope.destroied) $scope.timeout = setTimeout(function() { $scope.fetch(true); }, 1000);
								
							} else {
								$scope.items = data.items;
							}

							$scope.loadingItems = false;
							$scope.updating = false;
							callback();
						}
					});
					
					 */
				};

				$scope.$on('$destroy', function() {
					$scope.destroy = true;
					$scope.clearRunningStatuses();
				});

				$timeout($scope.fetch);

				$scope.close = function () { $uibModalInstance.close(); };
	}]);

});


define('controllers/queueLogViewer',['app'], function(app) {
	app.controller('queueLogViewer',
		["$uibModalInstance", "$scope", "$timeout", "consts", "group", "reload",
			function($uibModalInstance, $scope, $timeout, consts, group, reload) {
				$scope.group = group;

				$scope.autoScroll = true;
				$scope.logContent = null;
				$scope.timeout = null;

				$timeout(function () {
					$scope.logContent = document.getElementById('logContentQueue');
					$scope.logContent.scrollTop = $scope.logContent.scrollHeight

					$scope.logContent.addEventListener('scroll', function () {
						$scope.autoScroll = Math.abs($scope.logContent.scrollHeight - $scope.logContent.scrollTop - $scope.logContent.clientHeight) < 1;
					});
				});

				$scope.reloadLog = function () {
					$scope.timeout = null;

					reload(function(data) {
						$scope.group = data;

						$timeout(function () {
							if ($scope.autoScroll && $scope.logContent) $scope.logContent.scrollTop = $scope.logContent.scrollHeight;
						});

						if($scope.group.status < consts.QUEUE_STATUS_COMPLETED) $scope.timeout = setTimeout($scope.reloadLog, 2000);
					});
				}

				if($scope.group.status < consts.QUEUE_STATUS_COMPLETED) $scope.reloadLog();

				$scope.ok = function () { $uibModalInstance.close(); };

				$scope.$on('$destroy', function () {
					if($scope.timeout) clearTimeout($scope.timeout);
					$scope.timeout = null;
				});
			}
		]
	);
});


define('controllers/queuePriorities',[
	'app'
	], function(app) {
	app.controller("queuePriorities",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "$q", "api", "meta", "lang", "consts", "confirm", "alert",
			function ($rootScope, $scope, $location, $timeout, $interval, $q, api, meta, lang, consts, confirm, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.priorities = [];
				$scope.tags = {};
				$scope.loadingPriorities = false;
				$scope.loaders = {
					default: false,
					delete: false
				};

				meta = meta.new("queue_priorities");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name", "priority"]);
				meta.setTotalItems($scope.priorities.length);

				$scope.onClickDelete = function(priority) {

					if($scope.saveing) return;
					$scope.saveing = true;

					confirm.open({
						message: lang.t("This queue priority will be permanently deleted!"),
						confirm: function () {
							$scope.loaders.delete = true;
							api.deleteQueuePriority({ 
								data: { _id: priority._id }, 
								success: function(data, message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};

				$scope.setDefault = function (priority) {

					if($scope.saveing) return;
					$scope.saveing = true;

					$scope.loaders.default = true;
					api.manageQueuePriority({ 
						data: { action: 'modify', _id: priority._id, default: 1 }, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.loaders.default = false;
	
							for(var i =0 ; i < $scope.priorities.length; i++) {
								if($scope.priorities[i].default) {
									$scope.priorities[i].default = 0;
									break;
								}
							}
							priority.default = 1;
	
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							$scope.loaders.default = false;
							alert.error(message);
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingPriorities = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.priorities = [];

					api.listQueuePriorities({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.priorities);
							$scope.priorities = data.priorities;
							$scope.loadingPriorities = false;
						}
					});
				};

				$scope.fetchTags = function() {
					api.listTags({ 
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) $scope.tags[data.tags[i]._id] = data.tags[i];
						}
					});
				};

				$timeout(function () {
					$scope.fetchTags();
					$scope.fetch();
				});
			}
		]
	);
});


define('controllers/queuePriorityManage',[
	'app'
	], function(app) {
	app.controller("queuePriorityManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "consts", "lang", "meta", "util", "confirm", "alert", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, consts, lang, meta, util, confirm, alert, popup) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.details = {};
				$scope.saveData = {
					name: '',
					tags: [],
					backup_priority: '',
					clone_priority: '',
					restore_priority: '',
					download_priority: ''
				};

				$scope.tags = {};
				$scope.saveing 	= false;
				$scope.status 	= undefined;
				$scope.changed 	= false;
				$scope.cancelled = false;


				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/queuePriorities');
				};

				$scope.searchTags = function(query) {

					if(!query) return [];

					var deferred = $q.defer();

					api.listTags({ 
						data: { filter: query, sort: { name: 1 }, find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function(data) {
							var results = [];
							for(var i = 0; i < data.tags.length; i++) {
								var tag = data.tags[i];
								if($scope.saveData.tags.indexOf(tag._id) >= 0) continue;
								results.push(tag);
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.selectItem = function(item, obj) {
					if(item === undefined) return;
					$scope.saveData.tags.push(item._id);
					obj.searchItemText = '';
				};

				$scope.manageTags = function() {

					popup.open({
						template: 'tagsSelection',
						scope: $scope,
						resolve: {
							tags: function() { return $scope.saveData.tags; },
							type: function () { return consts.TAG_TYPE_ACCOUNT; }
						}
					}).result.then(function(selected) {
						$scope.saveData.tags = selected;
					}, function () {});

				};

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageQueuePriority({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/queuePriorityManage/' + data._id);
							else $location.path('/queuePriorities');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				$scope.fetch = function(priority_id) {
					api.getQueuePriority({ 
						data: { _id: priority_id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});

				};

				$scope.fetchTags = function() {
					api.listTags({ 
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) $scope.tags[data.tags[i]._id] = data.tags[i];
							var priority_id = $routeParams.id;
							if(priority_id) $timeout($scope.fetch(priority_id));
						}
					});
				};

				$timeout(function () {
					$scope.fetchTags();
				});

			}
		]
	);

});


define('controllers/security',['app'], function(app) {
	app.controller("security",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "meta", "confirm", "util", "lang", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, meta, confirm, util, lang, consts, alert) {
				$rootScope.$emit('menuItem', 'Security');


				$scope.saveing = false;
				$scope.loading = false;
				$scope.pluginTemplate = '';
				$scope.pluginsList = {};
				$scope.publicDir = '';
				$scope.plugins_available = {};
				$scope.plugin_available = {};

				$scope.saveData = {
					plugin: '',
					restore: 0,
					lock: 0,
					options: {}
				};

				$scope.plugins = [];

				$scope.isAvailablePlugins = function() {
					return $scope.saveData.plugin && $scope.saveData.plugin.indexOf('AvailablePlugins') >= 0;
				};

				$scope.changePlugin = function() {
					if(!$scope.saveData.plugin) {
						$scope.pluginTemplate = '';
						$scope.details = {};
						return;
					}

					if($scope.isAvailablePlugins()) {
						var parts = $scope.saveData.plugin.split("::");
						$scope.plugin_available = $scope.plugins_available[parts[1]];
						$scope.pluginTemplate = $scope.includePath('securityAvailablePlugins')
					} else {
						//$scope.saveData = util.duplicateObject($scope.pluginsList[$scope.plugin]);
						$scope.details = util.duplicateObject($scope.pluginsList[$scope.saveData.plugin]);
						lang.setDefaultNS('plugins-security-' + $scope.details.code);
						app.registerPluginController($scope.details, function(path) {
							$scope.publicDir = path;
							$scope.pluginTemplate = $scope.publicDir + '/view.htm?v=' + $scope.details.version;
						});
					}
				};

				$scope.installDestination = function() {

					if($scope.installing) return;
					$scope.installing = true;

					confirm.open({
						message: lang.t("This plugin will be installed on this server!"),
						confirm: function () {
							api.installPlugin({ 
								data: { package_id: $scope.plugin_available._id, disabled: 0 }, 
								success: function (data, message) {
									$scope.installing = false;
	
									//$scope.installed_plugin = response.data;
									$scope.plugin_available = {};
	
									$scope.fetch(function () {
	
										$scope.loading = false;
										$scope.saveData.plugin = '';
	
										for(var id in $scope.pluginsList) {
											if($scope.pluginsList[id].code === data.code) {
												$scope.saveData.plugin = id;
												break;
											}
										}
	
										$scope.changePlugin();
										alert.success(message);
									});
								},
								failed: function (message) {
									$scope.installing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.installing = false;
						}
					});
				};

				$scope.saveChanges = function(callback) {
					if($scope.saveing) return;
					if(callback === undefined || typeof callback !== 'function') callback = function() {};

					$scope.saveing = true;

					var apiParams = util.duplicateObject($scope.saveData);

					api.manageSecurityPlugin({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							callback();
							alert.success(message);
						},
						failed: function(message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				$scope.loadPackagesAvailable = function(callback) {
					
					if(callback === undefined || typeof callback !== 'function') callback = function(){};

					api.listPackagesAvailable({
						data: { find: { type: 'security' } },
						success: function (data) {
							for(var i = 0; i < data.packages.length; i++) {
								var pkg = data.packages[i];
								$scope.plugins_available[pkg.code] = pkg;
								$scope.plugins.push({ name: lang.t("%s via %s", pkg.name, pkg.repo_name), _id: "AvailablePlugins::" + pkg.code, group: lang.t('Available Plugins') });
							}

							callback();
						},
						failed: function (message) {
							callback();
						}
					});
				};
				
				$scope.fetch = function(callback) {

					if(callback === undefined || typeof callback !== 'function') callback = function(){};

					$scope.plugins = [ {_id: '', name: lang.t('Disabled') } ];
					$scope.pluginsList = {};
					$scope.plugins_available = {};

					$scope.loading = true;
					api.listPlugins({ 
						data: { find: { type: consts.PLUGIN_TYPE_SECURITY, disabled: false } }, 
						success: function (data) {

							for(var i = 0; i < data.plugins.length; i++) {
								$scope.plugins.push({_id: data.plugins[i]._id, name: data.plugins[i].name, group: lang.t("Installed Plugins")});
								$scope.pluginsList[data.plugins[i]._id] = data.plugins[i];
							}

							$scope.loadPackagesAvailable(callback);
						},
						failed: function () {
							$scope.loadPackagesAvailable(callback);
						}
					});
				};

				$scope.fetch(function () {
					api.getSettings({ 
						data: { section: 'security' },
						success: function (data) {
							$scope.loading = false;
							$scope.saveData = data;
							$scope.changePlugin();
						},
						failed: function (message) {
							alert.error(message);
						}
					}, function(response) {
					});
				});

			}]);
});


define('controllers/extension',['app'], function(app) {
	app.controller("extension",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "popup", "confirm", "util", "lang", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, popup, confirm, util, lang, consts, alert) {
				$rootScope.$emit('menuItem', 'Extension');

				$scope.excluderow = '';
				$scope.saving = false;
				$scope.loading = false;

				$scope.permissions = 0;
				$scope.details = {};
				$scope.saveData = {
					vendors: [],
					excludes: [],
					partner_token: ''
				};

				$scope.integrations = window.PAGE.wp_integrations;
				
				$scope.toggleVendor = function(vendor) {
					var index = $scope.saveData.vendors.indexOf(vendor);
					if (index > -1) $scope.saveData.vendors.splice(index, 1);
					else $scope.saveData.vendors.push(vendor);
				};
				
				$scope.isVendorEnabled = function (vendor) {
					return $scope.saveData.vendors.indexOf(vendor) >= 0;
				};
				
				$scope.addListRow = function () {

					const record = $scope.excluderow.trim();
					
					if(!/^([a-z0-9.\-\[\]*\/]+)$/.test(record)) alert.error(lang.t('The following sites ("%s") is invalid.', record));
					else if ($scope.saveData.excludes.indexOf(record) >= 0) alert.error(lang.t('The provided site(s) ("%s") already exists on the list.', record));
					else $scope.saveData.excludes.push(record);

					$scope.excluderow = '';
				};
				
				$scope.addMultiListRow = function() {

					$scope.listTitle = lang.t("Wordpress sites to exclude");
					$scope.listData = $scope.saveData.excludes.join("\n");

					$scope.listUIB = popup.open({
						template: 'listSelection',
						noController: true,
						scope: $scope
					});
					
					$scope.listUIB.result.then(function(records) {
						while($scope.saveData.excludes.length) $scope.saveData.excludes.pop();

						var invalidRecords = [];
						var duplicateRecords = [];

						records = records.split("\n");

						for(var i = 0; i < records.length; i++) {
							const record = records[i];
							
							if(!/^([a-z0-9.\-\[\]*\/]+)$/.test(record)) invalidRecords.push(record);
							else if ($scope.saveData.excludes.indexOf(record) >= 0) duplicateRecords.push(record);
							else $scope.saveData.excludes.push(record);
						}

						if(invalidRecords.length) alert.error(lang.t('The following sites ("%s") is invalid.', invalidRecords.join(", ") ))
						if(duplicateRecords.length) alert.error(lang.t('The provided site(s) ("%s") already exists on the list.', duplicateRecords.join(", ")));
					}, function () {});
				};

				$scope.togglePermissions = function() {

					var newStatus = $scope.permissions == 1 ? 0 : 1;
					api.managePermissions({
						data: {
							permissions: {
								[consts.PERMISSIONS_CAN_ACCESS_SOCKET_API]: newStatus
							}
						},
						success: function (data, message) {
							$scope.permissions = newStatus;
							console.log("AFTER:" + $scope.permissions)
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};
				
				$scope.massDeployment = function () {

					if($scope.deploy) return;
					$scope.deploy = true;

					api.runExtensionDeployment({
						success: function (data, message) {
							$scope.deploy = false;
							alert.success(message);
						},
						failed: function (message) {
							$scope.deploy = false;
							alert.error(message);
						}
					});

				};
				
				$scope.saveChanges = function () {
					if($scope.saving) return;
					$scope.saving = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function (key) { return key === 'vendors' });
					apiParams.section = 'extension';

					api.manageSettings({
						data: apiParams,
						success: function (data, message) {
							$scope.saving = false;
							alert.success(message);
						},
						failed: function (message) {
							$scope.saving = false;
							alert.error(message);
						}
					});

				};

				$scope.fetch = function() {
					$scope.loading = true;
					api.getSettings({
						data: { section: 'extension' },
						success: function(data) {
							api.getPermissions({
								success: function(prem_data) {
									console.log(prem_data.permissions[consts.PERMISSIONS_CAN_ACCESS_SOCKET_API]);
									$scope.permissions = prem_data.permissions[consts.PERMISSIONS_CAN_ACCESS_SOCKET_API];
									$scope.details = data;
									$scope.saveData = util.duplicateObject($scope.details);
									$scope.loading = false;
								},
								failed: function (message) {
									alert.error(message);
									$scope.loading = false;
								}
							});
						},
						failed: function (message) {
							alert.error(message);
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetch);

			}]);
});


define('controllers/support',['app'], function(app) {
	app.controller("support",
		["$rootScope", "$scope", "alert", "api", "lang",
			function ($rootScope, $scope, alert, api, lang) {
				$rootScope.$emit('menuItem', 'Support');

				$scope.cancel = function() {

					$scope.loading = false;
					$scope.wizard = 0;
					$scope.info = {};
					$scope.url = "";
					$scope.options = {
						configurations: false,
						access: false,
						whitelisted: false,
						sshkey: '1'
					};

				};

				$scope.cancel();

				$scope.setWizardStep = function(step) {
					$scope.wizard = step;
				};

				$scope.addSSHKey = function() {

					if($scope.options.access) {
						if(!$scope.options.whitelisted) {
							alert.error(lang.t("Please confirm all conditions"));
							return false;
						}

						if($scope.options.sshkey === '1') {
							// TODO add SSH Key
							$scope.loading = true;
						}
					}

					$scope.setWizardStep(3);
				};

				$scope.transmitData = function() {

					if(!$scope.options.configurations) {
						alert.error(lang.t("You must allow JetApps staff to review your configurations. If you don't want to let JetApps staff to review your configurations, Please open a ticket directly to JetApps Helpdesk at https://billing.jetapps.com/submitticket.php"));
						return false;
					}

					$scope.loading = true;
					api.createSupportTicketKey({
						success: function (data) {
							$scope.loading = false;
							$scope.info = data.info;
							$scope.key = data.key;
							$scope.ip = data.ip;
							$scope.url = $scope.info.url;
							$scope.url += ($scope.url.indexOf('?') >= 0) ? '&' : '?';
							$scope.url += "key=" + data.key + "&ip=" + data.ip + "&allowaccess=" + ($scope.options.access ? "yes" : "no");

							$scope.setWizardStep(2);
						},
						failed: function(message) {
							$scope.loading = false;
							alert.error(message);
						}
					});
				};

			}
		]
	);
});


define('controllers/repositories',['app'], function(app) {
	app.controller("repositories",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "filter", "confirm", "alert", "lang",
			function ($rootScope, $scope, $location, $timeout, api, meta, filter, confirm, alert, lang) {
				$rootScope.$emit('menuItem', 'Plugins');

				$scope.repositories = [];
				$scope.loadingRepositories = false;

				$scope.loaders = {
					reload: false,
					delete: false
				};

				meta = meta.new("repositories");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["created"]);
				meta.setTotalItems($scope.repositories.length);

				$scope.reloadDB = function(repository) {

					$scope.loaders.reload = true;

					api.reloadRepository({ 
						data: { _id: repository._id }, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.loaders.reload = false;
							repository.last_checked = data.last_checked;
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							$scope.loaders.reload = false;
							alert.error(message);
						}
					});
				};

				$scope.onClickDelete = function(repository) {

					if($scope.saveing) return;
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This repository will be permanently deleted!"),
						confirm: function () {
							api.deleteRepository({ 
								data: { _id: repository._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingRepositories = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.repositories = [];

					api.listRepositories({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.repositories);
							$scope.repositories = data.repositories;
							$scope.loadingRepositories = false;
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/repositoryManage',['app'], function(app) {
	app.controller("repositoryManage",
		["$rootScope", "$scope", "$location", "$routeParams", "$timeout", "api", "meta", "filter", "confirm", "lang", "util", "alert",
			function ($rootScope, $scope, $location, $routeParams, $timeout, api, meta, filter, confirm, lang, util, alert) {
				$rootScope.$emit('menuItem', 'Plugins');

				$scope.details = {
					name: '',
					url: ''
				};

				$scope.saveData = util.duplicateObject($scope.details);
				$scope.saveing = false;
				$scope.changed = true;
				$scope.cancelled = false;

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled) {
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/plugins/repositories');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageRepository({ 
						data: apiParams, 
						success: function(data, message) {

							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
	
							if(callback === undefined) {
								if(apply) $location.path('/repositoryManage/' + data._id);
								else $location.path('/plugins/repositories');
								alert.success(message);
							}
							
							if(callback !== undefined && typeof callback === 'function') callback();
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
							if(callback !== undefined && typeof callback === 'function') callback();
						}
					});
				};

				$scope.fetchRepoData = function() {
					api.getRepository({ 
						data: { _id: $routeParams.id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});
				};

				if($routeParams.id) $scope.fetchRepoData();
			}
		]
	);
});


define('controllers/filePermissions',['app'], function(app) {
	app.controller("filePermissions",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "$q", "api", "meta", "confirm", "lang", "alert",
			function ($rootScope, $scope, $location, $timeout, $interval, $q, api, meta, confirm, lang, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.permissions = [];
				$scope.loadingPermissions = false;
				$scope.loaders = {
					delete: false
				};

				meta = meta.new("file_permissions");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("regex");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["regex", "owner", "group", "permissions"]);
				meta.setTotalItems($scope.permissions.length);

				$scope.onClickDelete = function(permission) {

					if($scope.saveing) return;
					$scope.loaders.delete = true;
					$scope.saveing = true;

					confirm.open({
						message: lang.t("This file permission will be permanently deleted!"),
						confirm: function () {

							api.deleteFilePermissions({ 
								data: { _id: permission._id }, 
								success: function(data, message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.delete = false;
									$scope.saveing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.loaders.delete = false;
							$scope.saveing = false;
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingPermissions = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.permissions = [];

					api.listFilePermissions({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.permissions);
							$scope.permissions = data.permissions;
							$scope.loadingPermissions = false; 
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/filePermissionsManage',['app'], function(app) {
	app.controller("filePermissionsManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "util", "lang", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, util, lang, consts, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.details = {};
				$scope.saveData = {
					regex: '',
					category: consts.FILE_PERMISSIONS_CATEGORY_HOMEDIR_DATA,
					owner: '',
					group: '',
					recursive: 0,
					dirs_permissions: '',
					files_permissions: ''
				};

				$scope.saveing = false;
				$scope.changed = false;

				$scope.categories = [
					{_id: consts.FILE_PERMISSIONS_CATEGORY_HOMEDIR_DATA, name: consts.FILE_PERMISSIONS_CATEGORIES[consts.FILE_PERMISSIONS_CATEGORY_HOMEDIR_DATA] },
					{_id: consts.FILE_PERMISSIONS_CATEGORY_EMAIL_DATA, name: consts.FILE_PERMISSIONS_CATEGORIES[consts.FILE_PERMISSIONS_CATEGORY_EMAIL_DATA] }
				];

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageFilePermissions({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/filePermissionsManage/' + data._id);
							else $location.path('/filePermissions');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				$scope.fetch = function(permission_id) {
					api.getFilePermissions({ 
						data: { _id: permission_id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						}
					});

				};

				var permission_id = $routeParams.id;
				if(permission_id) $timeout($scope.fetch(permission_id));
			}
		]
	);

});


define('controllers/hooks',['app'], function(app) {
	app.controller("hooks",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "confirm", "alert", "lang", "consts",
			function ($rootScope, $scope, $location, $timeout, api, meta, confirm, alert, lang, consts) {
				$rootScope.$emit('menuItem', 'Hooks');

				$scope.hooks = [];
				$scope.loading = false;
				$scope.saveing = false;
				$scope.filter = '';
				$scope.filterOptions = [
					{ label: lang.t('All Hook Positions'), value: '' },
					{ label: lang.t('Pre'), value: consts.HOOK_TYPE_POSITION_PRE },
					{ label: lang.t('Post'), value: consts.HOOK_TYPE_POSITION_POST }
				];

				$scope.loaders = {
					delete: false,
					state: false
				};

				$scope.backups = {};
				$scope.clones = {};
				$scope.destinations = {};

				$scope.types = {};

				$scope.types[consts.BACKUP_TYPE_ACCOUNT] = lang.t("Accounts");
				$scope.types[consts.BACKUP_TYPE_DIRECTORY] = lang.t("Directories");

				$scope.positions = {};
				$scope.positions[consts.HOOK_POSITION_BACKUP] = lang.t("Backup");
				$scope.positions[consts.HOOK_POSITION_BACKUP_ACCOUNT] = lang.t("Backup Account");
				$scope.positions[consts.HOOK_POSITION_RESTORE] = lang.t("Restore");
				$scope.positions[consts.HOOK_POSITION_DOWNLOAD] = lang.t("Download");
				$scope.positions[consts.HOOK_POSITION_REINDEX] = lang.t("Reindex");
				$scope.positions[consts.HOOK_POSITION_SNAPSHOT] = lang.t("Snapshot");
				$scope.positions[consts.HOOK_POSITION_CLONE] = lang.t("Clone");
				$scope.positions[consts.HOOK_POSITION_CLONE_ACCOUNT] = lang.t("Clone Account");

				$scope.position_types = {};
				$scope.position_types[consts.HOOK_TYPE_POSITION_PRE] = lang.t("Pre");
				$scope.position_types[consts.HOOK_TYPE_POSITION_POST] = lang.t("Post");

				meta = meta.new("hooks");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","position_type","position","owner","disabled"]);
				meta.setTotalItems($scope.hooks.length);

				$scope.onClickDelete = function(hook) {

					if($scope.saveing) return;

					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This hook will be permanently deleted!"),
						confirm: function () {
							api.deleteHook({ 
								data: { _id: hook._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.toggleStatus = function(hook) {

					$scope.loaders.state = true;

					var disabled = !hook.disabled;

					api.manageHook({
						data: {
							_id: hook._id,
							action: 'modify',
							disabled: disabled
						},
						success: function(data, message) {
							$scope.loaders.state = false;
							hook.disabled = disabled;
							alert.success(message);
						},
						failed: function (message) {
							$scope.loaders.state = false;
							alert.error(message);
						}
					});
				};

				$scope.init = false;
				$scope.fetch = function(init) {

					if(!$scope.init && !init) return;
					$scope.init = true;

					$scope.loading = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					if($scope.filter) apiParams.find.position_type = $scope.filter;

					$scope.hooks = [];

					api.listHooks({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.hooks);
	
							for(var i = 0; i < data.hooks.length; i++) {
	
								var list = data.hooks[i].data_list;
	
								if(list.length) {
									switch(data.hooks[i].position) {
										case consts.HOOK_POSITION_BACKUP:
										case consts.HOOK_POSITION_BACKUP_ACCOUNT:
											for(var j = 0; j < list.length; j++) list[j] = ($scope.backups[list[j]] !== undefined) ? $scope.backups[list[j]].name : 'Unknown';
											break;
	
										case consts.HOOK_POSITION_RESTORE:
										case consts.HOOK_POSITION_DOWNLOAD:
											for(var j = 0; j < list.length; j++) list[j] = ($scope.types[list[j]] !== undefined) ? $scope.types[list[j]] : 'Unknown';
											break;
	
										case consts.HOOK_POSITION_REINDEX:
											for(var j = 0; j < list.length; j++) list[j] = ($scope.destinations[list[j]] !== undefined) ? $scope.destinations[list[j]].name : 'Unknown';
											break;
									}
								}
	
								$scope.hooks.push(data.hooks[i]);
	
							}
	
							$scope.loading = false;
						},
						failed: function (message) {
							alert.error(message)
						}
					});
				};

				api.listBackupJobs({ 
					success: function(data) {
						for(var i = 0; i < data.jobs.length; i++) $scope.backups[data.jobs[i]._id] = data.jobs[i];
	
						api.listDestinations({ 
							success: function(data) {
								for(var i = 0; i < data.destinations.length; i++) $scope.destinations[data.destinations[i]._id] = data.destinations[i];
								$timeout($scope.fetch(true));
							}
						});
					}
				});
			}
		]
	);
});


define('controllers/hookManage',['app'], function(app) {
	app.controller("hookManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "util", "lang", "consts", "confirm", "cfpLoadingBar", "alert", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, util, lang, consts, confirm, cfpLoadingBar, alert, popup) {
				$rootScope.$emit('menuItem', 'Hooks');

				$scope.details = {};
				$scope.saveData = {
					name: '',
					position_type: consts.HOOK_POSITION_BACKUP,
					position: consts.HOOK_TYPE_POSITION_PRE,
					data_list: [],
					script: ''
				};

				$scope.saveing = false;

				$scope.changed = false;
				$scope.cancelled = false;

				$scope.backups = {};
				$scope.clones = {};
				$scope.destinations = {};

				$scope.positions = [
					{ label: lang.t("Backup"), value: consts.HOOK_POSITION_BACKUP },
					{ label: lang.t("Backup Account"), value: consts.HOOK_POSITION_BACKUP_ACCOUNT },
					{ label: lang.t("Clone"), value: consts.HOOK_POSITION_CLONE },
					{ label: lang.t("Clone Account"), value: consts.HOOK_POSITION_CLONE_ACCOUNT },
					{ label: lang.t("Restore"), value: consts.HOOK_POSITION_RESTORE },
					{ label: lang.t("Download"), value: consts.HOOK_POSITION_DOWNLOAD },
					{ label: lang.t("Reindex"), value: consts.HOOK_POSITION_REINDEX }
					//{ label: lang.t("Snapshot"), value: consts.HOOK_POSITION_SNAPSHOT }
				];

				$scope.position_types = [
					{ label: lang.t("Pre"), value: consts.HOOK_TYPE_POSITION_PRE },
					{ label: lang.t("Post"), value: consts.HOOK_TYPE_POSITION_POST }
				];

				$scope.types = {};
				$scope.types[consts.HOOK_POSITION_RESTORE] = [
					{label:lang.t("Accounts"), value: consts.BACKUP_TYPE_ACCOUNT}//,
					//{label:lang.t("Directories"), value: consts.BACKUP_TYPE_DIRECTORY}
				];

				$scope.types[consts.HOOK_POSITION_DOWNLOAD] = [
					{label:lang.t("Accounts"), value: consts.BACKUP_TYPE_ACCOUNT}//,
					//{label:lang.t("Directories"), value: consts.BACKUP_TYPE_DIRECTORY}
				];

				$scope.itemsSelection = function () {

					var types = {};
					types[consts.HOOK_POSITION_BACKUP] = { template: 'backupJobsSelection', resolve: { jobs: function() { return $scope.saveData.data_list; } } };
					types[consts.HOOK_POSITION_BACKUP_ACCOUNT] = types[consts.HOOK_POSITION_BACKUP];
					types[consts.HOOK_POSITION_CLONE] = { template: 'cloneJobsSelection', resolve: { jobs: function() { return $scope.saveData.data_list; } } };
					types[consts.HOOK_POSITION_CLONE_ACCOUNT] = types[consts.HOOK_POSITION_CLONE];
					types[consts.HOOK_POSITION_REINDEX] = { template: 'destinationsSelection', controller: 'destinationsSelection', resolve: { destinations: function() { return $scope.saveData.data_list; }, readonly: function () { return true; }, types: function () { return consts.DESTINATION_JOB_TYPE_BACKUP; }, legacy: function () { return true; }, local: function () { return true; }, timebased: function () { return true; } } };

					if(types[$scope.saveData.position] === undefined) return;

					popup.open(types[$scope.saveData.position]).result.then(function(selected) {
						$scope.saveData.data_list = selected;
					}, function () {
						//$log.info('Modal dismissed at: ' + new Date());
					});
				};

				$scope.searchCloneJobs = function(query) {

					if(query)
					{
						var deferred = $q.defer();

						api.listCloneJobs({
							data: { filter: query, sort: { name: 1 } },
							success: function(data) {
								var result = [];
								for(var i = 0; i < data.jobs.length; i++) {
									if($scope.saveData.data_list.indexOf(data.jobs[i]._id) >= 0) continue;

									var job = data.jobs[i];
									var type = parseInt(job.type);
									var contains = parseInt(job.contains);
									var names = [];


									switch(type) {
										case consts.CLONE_TYPE_ACCOUNT:
											if(contains == consts.CLONE_TYPE_ACCOUNT_FULL) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_FULL]);
											else {
												if(contains & consts.CLONE_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_HOMEDIR) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_HOMEDIR]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_DATABASES) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASES]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_EMAILS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_EMAILS]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CRON_JOBS]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_DOMAINS) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DOMAINS]);
												if(contains & consts.CLONE_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CERTIFICATES]);
											}
											break;
											/*
										case consts.CLONE_TYPE_DIRECTORY:
											names.push(consts.CLONE_TYPE_DIRECTORY_NAMES[consts.CLONE_TYPE_DIRECTORY_FULL]);
											break;
											
											 */
									}

									job.contains_name = names.join(', ');

									result.push(job);
								}
								deferred.resolve(result);
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.searchBackupJobs = function(query) {

					if(query)
					{
						var deferred = $q.defer();

						api.listBackupJobs({ 
							data: { filter: query, sort: { name: 1 } }, 
							success: function(data) {
								var result = [];
								for(var i = 0; i < data.jobs.length; i++) {
									if($scope.saveData.data_list.indexOf(data.jobs[i]._id) >= 0) continue;

									var job = data.jobs[i];
									var type = parseInt(job.type);
									var contains = parseInt(job.contains);
									var names = [];


									switch(type) {
										case consts.BACKUP_TYPE_ACCOUNT:
											if(contains == consts.BACKUP_TYPE_ACCOUNT_FULL) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL]);
											else {
												if(contains & consts.BACKUP_TYPE_ACCOUNT_CONFIG) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_HOMEDIR) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_DATABASES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_EMAILS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_DOMAINS) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS]);
												if(contains & consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES) names.push(consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES]);
											}
											break;
										case consts.BACKUP_TYPE_DIRECTORY:
											names.push(consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL]);
											break;
									}

									job.contains_name = names.join(', ');

									result.push(job);
								}
								deferred.resolve(result);
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.searchDestinations = function(query) {

					if(query)
					{
						var deferred = $q.defer();

						api.listDestinations({ 
							data: { filter: query, sort: { name: 1 } }, 
							success: function(data) {
								var result = [];
								for(var i = 0; i < data.destinations.length; i++) {
									if($scope.saveData.data_list.indexOf(data.destinations[i]._id) >= 0) continue;
									result.push(data.destinations[i]);
								}
								deferred.resolve(result);
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.selectItem = function(item, obj) {
					if(item === undefined) return;
					$scope.saveData.data_list.push(item._id);
					obj.searchBackupText = '';
					obj.searchCloneText = '';
					obj.searchDestinationText = '';
				};

				$scope.fetchHookData = function(hook_id) {

					api.getHook({ 
						data: { _id: hook_id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						},
						failed: function () {
							$location.path('/hooks');
						}
					});
				};

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.resetList = function() {
					$scope.saveData.data_list = [];
				};

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.manageTypesList = function(type) {
					var index = $scope.saveData.data_list.indexOf(type);
					if(index >= 0) $scope.saveData.data_list.splice(index, 1);
					else $scope.saveData.data_list.push(type);
				};

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/hooks');
				};

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageHook({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/hookManage/' + data._id);
							else $location.path('/hooks');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				api.listBackupJobs({ 
					success: function(data) {
						for(var i = 0; i < data.jobs.length; i++) $scope.backups[data.jobs[i]._id] = data.jobs[i];
					}
				});

				api.listCloneJobs({
					success: function(data) {
						for(var i = 0; i < data.jobs.length; i++) $scope.clones[data.jobs[i]._id] = data.jobs[i];
					}
				});

				api.listDestinations({ 
					success: function(data) {
						for(var i = 0; i < data.destinations.length; i++) $scope.destinations[data.destinations[i]._id] = data.destinations[i];
					}
				});

				var hook_id = $routeParams.id;
				if(hook_id) $timeout($scope.fetchHookData(hook_id));
				else cfpLoadingBar.complete();
	}]);
});


define('controllers/tags',['app'], function(app) {
	app.controller("tags",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "confirm", "alert", "lang", "consts",
			function ($rootScope, $scope, $location, $timeout, api, meta, confirm, alert, lang, consts) {
				$rootScope.$emit('menuItem', 'Accounts');

				$scope.tags = [];
				$scope.loading = false;
				$scope.saveing = false;

				$scope.filter = '';
				/*
				$scope.filterOptions = [
					{ label: lang.t('All Tag Types'), value: '' },
					{ label: lang.t('Account'), value: consts.TAG_TYPE_ACCOUNT },
				];

				 */

				$scope.types = {};
				$scope.types[consts.TAG_TYPE_ACCOUNT] = lang.t('Account');

				$scope.loaders = {
					delete: false
				};

				meta = meta.new("tags");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","color","owner"]);
				meta.setTotalItems($scope.tags.length);

				$scope.onClickDelete = function(tag) {

					if($scope.saveing) return;

					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This tag will be permanently deleted, also this tag will be removed from all accounts that are using it!"),
						confirm: function () {
							api.deleteTag({ 
								data: { _id: tag._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.fetch = function() {

					if($scope.loading) return;
					$scope.loading = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					if($scope.filter) apiParams.find.type = $scope.filter;

					$scope.tags = [];

					api.listTags({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.tags);
							$scope.tags = data.tags;
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetch());
			}
		]
	);
});


define('controllers/tagManage',['app'], function(app) {
	app.controller("tagManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "util", "lang", "consts", "confirm", "cfpLoadingBar", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, util, lang, consts, confirm, cfpLoadingBar, alert) {
				$rootScope.$emit('menuItem', 'Accounts');

				var randomColor = function() {
					var letters = '0123456789ABCDEF';
					var color = '#';
					for (var i = 0; i < 6; i++) {
						color += letters[Math.floor(Math.random() * 16)];
					}
					return color.toLowerCase();
				};

				$scope.details = {};
				$scope.saveData = {
					name: '',
					type: consts.TAG_TYPE_ACCOUNT,
					color: randomColor(),
				};

				$scope.saveing = false;

				$scope.changed = false;
				$scope.cancelled = false;

				$scope.colors = [
					'#3e3c3e',
					'#666366',
					'#8d8a8d',
					'#b4b2b4',
					'#e5a8de',
					'#d87bcc',
					'#cb4dba',
					'#ab329b',
					'#7e2572',
					'#511849',
					'#900c3f',
					'#c70039',
					'#ff5733',
					'#ff8d1a',
					'#ffc300',
					'#eddd53',
					'#add45c',
					'#57c785',
					'#00baad',
					'#2a7b9b',
					'#3d3d6b',
					'#6464a6',
					'#4848c2',
					'#2c2cde'];

				$scope.types = [
					{label:lang.t("Account"), value: consts.TAG_TYPE_ACCOUNT}
				];

				$scope.randomColor = function() {
					$scope.saveData.color = randomColor();
				};

				$scope.fetchTagData = function(tag_id) {

					api.getTag({ 
						data: { _id: tag_id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
						},
						failed: function () {
							$location.path('/tags');
						}
					});
				};

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled)
					{
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/tags');
				};

				$scope.saveChanges = function(apply) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageTag({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/tagManage/' + data._id);
							else $location.path('/tags');
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
						}
					});
				};

				var tag_id = $routeParams.id;
				if(tag_id) $timeout($scope.fetchTagData(tag_id));
				else cfpLoadingBar.complete();
	}]);
});


define('controllers/tagsSelection',['app'], function(app) {

	app.controller('tagsSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "lang", "tags", "type",
			function($uibModalInstance, $scope, $timeout, api, lang, tags, type) {

				$scope.loading = false;
				$scope.tags = [];

				$scope.fetchTags = function () {

					$scope.loading = true;

					api.listTags({ 
						data: { find: { type: type }, sort: { name: 1 } }, 
						success: function (data) {
							for (var i = 0; i < data.tags.length; i++) {
								data.tags[i].checked = tags !== undefined && tags.length ? tags.indexOf(data.tags[i]._id) >= 0 : false;
								$scope.tags.push(data.tags[i]);
							}
								
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchTags());

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.tags.length; i++) {
						if($scope.tags[i].checked) selected.push($scope.tags[i]._id);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/destinationsSelection',['app'], function(app) {

	app.controller('destinationsSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "lang", "meta", "destinations", "readonly", "types", "legacy", "local", "timebased",
			function($uibModalInstance, $scope, $timeout, api, lang, meta, destinations, readonly, types, legacy, local, timebased) {

				$scope.loading = false;
				$scope.destinations = [];

				$scope.fetchDestinations = function () {

					$scope.loading = true;

					api.listDestinations({ 
						data: {
							types: types,
							readonly: readonly, 
							sort: { name: 1 } 
						}, 
						success: function (data) {

							for (var i = 0; i < data.destinations.length; i++) {
								if(!legacy && data.destinations[i].legacy) continue; 
								if(!timebased && data.destinations[i].time_based) continue; 
								if(!local && (data.destinations[i].type == 'Local' || data.destinations[i].type == 'Localv2')) continue; 
								data.destinations[i].checked = destinations !== undefined && destinations.length ? destinations.indexOf(data.destinations[i]._id) >= 0 : false;
								$scope.destinations.push(data.destinations[i]);
							}
	
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchDestinations);

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.destinations.length; i++) {
						if($scope.destinations[i].checked) selected.push($scope.destinations[i]._id);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/backupJobsSelection',['app'], function(app) {

	app.controller('backupJobsSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "lang", "meta", "jobs",
			function($uibModalInstance, $scope, $timeout, api, lang, meta, jobs) {

				$scope.loading = false;
				$scope.jobs = [];

				$scope.fetchJobs = function () {

					$scope.loading = true;

					api.listBackupJobs({ 
						data: { sort: { name: 1 } }, 
						success: function (data) {
							for (var i = 0; i < data.jobs.length; i++) {
								data.jobs[i].checked = jobs !== undefined && jobs.length ? jobs.indexOf(data.jobs[i]._id) >= 0 : false;
							}
	
							$scope.jobs = data.jobs;
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchJobs());

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.jobs.length; i++) {
						if($scope.jobs[i].checked) selected.push($scope.jobs[i]._id);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/cloneJobsSelection',['app'], function(app) {

	app.controller('cloneJobsSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "lang", "meta", "jobs",
			function($uibModalInstance, $scope, $timeout, api, lang, meta, jobs) {

				$scope.loading = false;
				$scope.jobs = [];

				$scope.fetchJobs = function () {

					$scope.loading = true;

					api.listCloneJobs({ 
						data: { sort: { name: 1 } }, 
						success: function (data) {
							for (var i = 0; i < data.jobs.length; i++) {
								data.jobs[i].checked = jobs !== undefined && jobs.length ? jobs.indexOf(data.jobs[i]._id) >= 0 : false;
							}
	
							$scope.jobs = data.jobs;
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchJobs());

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.jobs.length; i++) {
						if($scope.jobs[i].checked) selected.push($scope.jobs[i]._id);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/backupLockSelection',[
	'app',
	], function(app) {
	app.controller('backupLockSelection', ["$uibModalInstance", "$scope", "lang",
		function($uibModalInstance, $scope, lang) {
			$scope.ttl = 0;
			$scope.ok = function () { $uibModalInstance.close($scope.ttl); };
			$scope.cancel = function () { $uibModalInstance.dismiss(lang.t('cancel')); };
		}
	]);
});


define('controllers/plugins',['app'], function(app) {
	app.controller("plugins",
		["$rootScope", "$scope", "$routeParams", "$location", "lang",
			function ($rootScope, $scope, $routeParams, $location, lang) {
				$rootScope.$emit('menuItem', 'Plugins');

				$scope.plugins = [];
				$scope.loadingPlugins = false;

				$scope.loaders = {
					state: false,
					uninstall: false
				};

				$scope.sections = [
					{_id: "installed",name: lang.t("Installed Plugins"),icon:"fa-edit",template: $scope.includePath("pluginManage")},
					{_id: "packages",name: lang.t("Available Plugins"),icon:"fa-box",template: $scope.includePath("packages")},
					{_id: "repositories",name: lang.t("Repositories"),icon:"fa-layer-group",template: $scope.includePath("repositories")}
				];

				$scope.getSection = function (section_id) {
					for(var i = 0; i < $scope.sections.length; i++) {
						if($scope.sections[i]._id === section_id) {
							return $scope.sections[i];
						}
					}

					return $scope.sections[0];
				};

				$scope.changeSection = function (section) {
					if($routeParams.section === section._id) $scope.currentSection = section;
					$location.path('/plugins/' + section._id);
				};

				$scope.changeSection($scope.getSection($routeParams.section ? $routeParams.section : $scope.sections[0]._id));
			}
		]
	);
});


define('controllers/packages',['app'], function(app) {
	app.controller("packages",
		["$rootScope", "$scope", "$location", "$timeout", "api", "lang", "confirm", "alert", "meta", "consts",
			function ($rootScope, $scope, $location, $timeout, api, lang, confirm, alert, meta, consts) {
				$rootScope.$emit('menuItem', 'Plugins');

				/*
				$scope.installing = false;
				$scope.package = '';
				$scope.packages = [
					{value: '', label: lang.t("Select Package")}
				];

				api.listAvailablePlugins({}, function (response) {
					if(!response.success) return;
					for(var i = 0; i < response.data.plugins.length; i++) {
						$scope.packages.push({ value: response.data.plugins[i], label: response.data.plugins[i]});
					}
				});

				$scope.install = function() {
					if($scope.installing) return;
					$scope.installing = true;

					api.installPlugin({ "package_name": $scope.package }, function (response) {
						$scope.installing = false;
						if(response.success) alert.success(response.message);
						else alert.error(response.message);
					});
				};

				 */


				$scope.packages = [];
				$scope.filterRepos = [{ label: lang.t('All Repositories'), value: '' }];
				$scope.repo = '';
				$scope.filterTypes = [
					{ value: '', label: lang.t('All Types') },
					{ value: consts.PLUGIN_TYPE_DESTINATION, label: lang.t("Destinations") },
					{ value: consts.PLUGIN_TYPE_NOTIFICATION, label: lang.t("Notification") },
					{ value: consts.PLUGIN_TYPE_SECURITY, label: lang.t("Security") },
					{ value: consts.PLUGIN_TYPE_ADDON, label: lang.t("Addons") }
				];
				$scope.type = '';
				$scope.loadingPackages = false;

				$scope.loaders = {
					install: false
				};

				meta = meta.new("packages");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([30,60,120,240]);
				meta.setPageSize(30);
				meta.setSortFields(["created"]);
				meta.setTotalItems($scope.packages.length);

				$scope.switchRepo = function(packageData) {
					confirm.open({
						message: lang.t("Are you sure you want to switch this plugin installation to the repository \"%s\"? This plugin will start picking up updates from this repository", packageData.repo_name),
						confirm: function () {
							api.managePlugin({ 
								data: { _id: packageData.plugin_id, repo: packageData.repo }, 
								success: function(data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.uninstall = function(packageData) {
					confirm.open({
						message: lang.t("This plugin and all his settings will be permanently deleted!"),
						confirm: function () {
							api.uninstallPlugin({ 
								data: { _id: packageData.plugin._id }, 
								success: function(data, message) {
									$scope.loaders.uninstall = false;
									if($rootScope.plugins[packageData.plugin._id] !== undefined) {
										$rootScope.plugins[packageData.plugin._id].visible = false;
										$rootScope.plugins[packageData.plugin._id].disabled = true;
									}
	
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.uninstall = false;
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.reinstall = function(packageData) {
					confirm.open({
						message: lang.t("This plugin will be reinstalled!"),
						confirm: function () {
							api.installPlugin({
								data: { package_id: packageData._id },
								success: function (data, message) {
									packageData.installed = true;
									packageData.installable = false;

									if(data.type == consts.PLUGIN_TYPE_ADDON)
										$rootScope.plugins[data._id] = data;

									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};
				
				$scope.install = function(packageData) {
					confirm.open({
						message: lang.t("This plugin will be installed on this server!"),
						confirm: function () {
							api.installPlugin({ 
								data: { package_id: packageData._id }, 
								success: function (data, message) {
									packageData.installed = true;
									packageData.installable = false;
	
									if(data.type == consts.PLUGIN_TYPE_ADDON)
										$rootScope.plugins[data._id] = data;
	
									$scope.fetch();
									alert.success(message);

									confirm.open({
										message: lang.t("Would you like to enable this plugin?"),
										confirmLabel: lang.t("Enable Plugin"),
										confirm: function () {
											api.managePlugin({
												data: { _id: data._id, disabled: false, visible: data.type == consts.PLUGIN_TYPE_ADDON },
												success: function(data, message) {

													if($rootScope.plugins[data._id] !== undefined) {
														for(var key in $rootScope.plugins[data._id])
															$rootScope.plugins[data._id][key] = data[key];
													}

													alert.success(message);
												},
												failed: function (message) {
													alert.error(message);
												}
											});
										}
									});
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.update = function(packageData) {

					confirm.open({
						message: lang.t("This plugin will be updated to version %s", packageData.version),
						confirm: function () {
							api.updatePlugin({ 
								data: { _id: packageData.plugin._id }, 
								success: function(data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingPackages = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					if($scope.repo) apiParams.find.repo = $scope.repo;
					if($scope.type) apiParams.find.type = $scope.type;

					$scope.packages = [];

					api.listPackages({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.packages);
							$scope.packages = data.packages;
							$scope.loadingPackages = false;
						}
					});
				};

				api.listRepositories({ 
					success: function (data) {
						for(var i = 0; i < data.repositories.length; i++) {
							$scope.filterRepos.push({ label: data.repositories[i].name, value: data.repositories[i]._id });
						}
					}
				});


				$timeout($scope.fetch);

			}
		]
	);
});


define('controllers/showcase',['app'], function(app) {
	app.controller("showcase",
		["$rootScope", "$scope", "$controller", "$q", "$location", "$timeout", "api", "permissions", "alert",
			function ($rootScope, $scope, $controller, $q, $location, $timeout, api, permissions, alert) {

				var showcases = window.PAGE.showcase;
				if(!showcases.total_unapproved) $location.path('/');
				
				$scope.showcases = {};
				$scope.features = {};
				for (var i = 0 ; i < showcases.total; i++) {
					if(showcases.features[i].approved) continue;
					var controllerName = showcases.features[i].feature + showcases.features[i].order;
					$scope.showcases[controllerName] = showcases.features[i];

					app.registerShowcaseController(showcases.features[i], function (path, controllerName) {
						$scope.features[controllerName] = $scope.showcases[controllerName];
					});
				}

				$scope.checkFeatures = function() {
					if(window.PAGE.showcase.total_unapproved > 0) return false;
					permissions.init(window.PAGE.permissions);
					$location.path('/');
				};

				$scope.setStatus = function(message) {
					alert.error(message);
				};

				$rootScope.$on('approve', function(event, feature) {
					var controllerName = feature.feature + feature.order;

					api.approveShowcase({ 
						data: { _id: feature._id }, 
						success: function () {
							window.PAGE.showcase.total_unapproved--;
							$scope.features[controllerName].approved = true;
							$scope.checkFeatures();
						},
						failed: function (message) {
							$scope.setStatus(message);
						}
					});
				});

				$rootScope.$on('error', function(event, error) { $scope.setStatus(error); });

				$scope.saveChanges = function() {
					$rootScope.$broadcast('save');
				};
			}
		]
	);
});


define('controllers/plugin',['app'], function(app) {
	app.controller("plugin",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "lang", "api", "util", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, lang, api, util, consts, alert) {

				if(!$routeParams.plugin) {
					$location.path('/');
					return;
				}

				$rootScope.$emit('menuItem', 'Plugin' + $routeParams.plugin);

				$scope.plugin = {};
				$scope.saveData = {};
				$scope.saveing = false;
				$scope.pluginView = '';
				$scope.publicDir = '';

				api.getPlugin({
					data: { code: $routeParams.plugin, type: consts.PLUGIN_TYPE_ADDON },
					success: function (data) {
						if(data.disabled || !data.visible) {
							$location.path('/');
							return;
						}
						$scope.plugin = data;
						$scope.saveData = util.duplicateObject($scope.plugin);

						lang.setDefaultNS('plugins-addon-' + $scope.plugin.code);
	
						app.registerPluginController($scope.plugin, function(path) {
							$scope.publicDir = path;
							$scope.pluginView = $scope.publicDir + '/view.htm?v=' + $scope.plugin.version;
						});
					},
					failed: function () {
						$location.path('/');
					}
				});

				$scope.saveChanges = function(callback) {
					if($scope.saveing) return;
					if(callback !== undefined || typeof callback !== 'function') callback = function() {};

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.plugin);

					api.managePlugin({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							callback();
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							callback();
							alert.error(message);
						}
					});
				};
			}
		]
	);
});


define('controllers/pluginManage',['app'], function(app) {
	app.controller("pluginManage",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "filter", "confirm", "alert", "lang", "consts",
			function ($rootScope, $scope, $location, $timeout, api, meta, filter, confirm, alert, lang, consts) {
				$rootScope.$emit('menuItem', 'Plugins');

				$scope.plugins = [];
				$scope.loadingPlugins = false;
				$scope.filter = '';
				$scope.filterOptions = [
					{ value: '', label: lang.t("All Plugins") },
					{ value: consts.PLUGIN_TYPE_DESTINATION, label: lang.t("Destination Plugins") },
					{ value: consts.PLUGIN_TYPE_NOTIFICATION, label: lang.t("Notification Plugins") },
					{ value: consts.PLUGIN_TYPE_SECURITY, label: lang.t("Security Plugins") },
					{ value: consts.PLUGIN_TYPE_ADDON, label: lang.t("Addon Plugins") }
				];

				$scope.loaders = {
					state: false,
					update: false,
					visible: false,
					autoupdate: false,
					uninstall: false
				};

				$scope.permissions = [
					{ value: consts.PLUGIN_PERMISSION_ROOT, name: lang.t("Root Access") },
					{ value: consts.PLUGIN_PERMISSION_RESELLER, name: lang.t("Root & Reseller Access") },
					{ value: consts.PLUGIN_PERMISSION_USER, name: lang.t("Root, Reseller & User Access") }
				];

				meta = meta.new("plugins_manage");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["created"]);
				meta.setTotalItems($scope.plugins.length);

				$scope.savePermissions = function(plugin) {
					api.managePlugin({ 
						data: { _id: plugin._id, permissions: plugin.permissions }, 
						success: function (data) {
							$scope.updatePlugin(data);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.updatePlugin = function(plugin) {
					if($rootScope.plugins[plugin._id] === undefined) return;
					for(var key in $rootScope.plugins[plugin._id])
						$rootScope.plugins[plugin._id][key] = plugin[key];
				};

				$scope.uninstall = function(plugin) {
					if($scope.loaders.uninstall) return;
					$scope.loaders.uninstall = true;

					confirm.open({
						message: lang.t("This plugin and all his settings will be permanently deleted!"),
						confirm: function () {
							api.uninstallPlugin({ 
								data: { _id: plugin._id }, 
								success: function(data, message) {
									$scope.loaders.uninstall = false;
									if($rootScope.plugins[plugin._id] !== undefined) {
										$rootScope.plugins[plugin._id].visible = false;
										$rootScope.plugins[plugin._id].disabled = true;
									}
	
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.uninstall = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.loaders.uninstall = false;
						}
					});
				};

				$scope.toggleStatus = function(plugin) {
					$scope.loaders.state = true;
					api.managePlugin({ 
						data: { _id: plugin._id, disabled: !plugin.disabled }, 
						success: function(data) {
							$scope.loaders.state = false;
							plugin.disabled = data.disabled;
							$scope.updatePlugin(data);
						},
						failed: function (message) {
							$scope.loaders.state = false;
							alert.error(message);
						}
					});
				};

				$scope.toggleVisible = function(plugin) {
					$scope.loaders.visible = true;
					api.managePlugin({ 
						data: { _id: plugin._id, visible: !plugin.visible }, 
						success: function(data) {
							$scope.loaders.visible = false;
							plugin.visible = data.visible;
							$scope.updatePlugin(data); 
						},
						failed: function (message) {
							$scope.loaders.visible = false;
							alert.error(message);
						}
					});
				};

				$scope.autoupdate = function(plugin) {
					if(plugin.updating) return;
					$scope.loaders.update = true;

					confirm.open({
						message: lang.t("This plugin will be updated to version %s", plugin.available_package),
						confirm: function () {
							plugin.updating = true;
							api.updatePlugin({ 
								data: { _id: plugin._id }, 
								success: function(data) {
									plugin.updating = false;
									$scope.loaders.update = false;
									plugin.version = data.version;
									plugin.available_package = data.available_package;
									$scope.updatePlugin(data);
								},
								failed: function (message) {
									$scope.loaders.update = false;
									alert.error(message);
								}

							});
						},
						cancel: function () {
							$scope.loaders.update = false;
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingPlugins = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					if($scope.filter) apiParams.find.type = $scope.filter;

					$scope.plugins = [];

					api.listPlugins({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.plugins);
							$scope.plugins = data.plugins;
							$scope.loadingPlugins = false;
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/logs',['app'], function(app) {
	app.controller("logs",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "filter", "confirm", "$interval", "lang", "consts", "alert", "popup",
			function ($rootScope, $scope, $location, $timeout, api, meta, filter, confirm, $interval, lang, consts, alert, popup) {
				$rootScope.$emit('menuItem', 'Logs');

				$scope.logs = [];
				$scope.logsProcessingList = {};
				$scope.checkTimeout = undefined;
				$scope.loadingLogs = false;
				$scope.showPager = true;
				$scope.checkall = false;
				$scope.checked = false;

				var logsFilter = filter.new("logs_filter");
				if(!logsFilter.getFilter()) logsFilter.setFilter(0);
				var filterSession = logsFilter.getFilter();
				$scope.filter = filterSession;
				// removed selected after first display
				logsFilter.setFilter(0);

				var logsSubFilter = filter.new("logs_subfilter");
				$scope.subfilter = logsSubFilter.getFilter();
				$scope.statusfilter = 0;
				// removed selected after first display
				logsSubFilter.setFilter("");

				$scope.subfilterTitle = '';
				$scope.subfilterOptions = [];
				$scope.filterOptions = [
					{ label: lang.t('All Logs'), value: 0 },
					{ label: lang.t('Backup Logs'), value: consts.LOG_TYPE_BACKUP },
					{ label: lang.t('Clone Logs'), value: consts.LOG_TYPE_CLONE },
					{ label: lang.t('Backup on Demand Logs'), value: consts.LOG_TYPE_BACKUP_ON_DEMAND },
					{ label: lang.t('Download Logs'), value: consts.LOG_TYPE_DOWNLOAD },
					{ label: lang.t('Restore Logs'), value: consts.LOG_TYPE_RESTORE },
					{ label: lang.t('Reindex Logs'), value: consts.LOG_TYPE_REINDEX },
					{ label: lang.t('System Logs'), value: consts.LOG_TYPE_SYSTEM },
					{ label: lang.t('Extension Installation Logs'), value: consts.LOG_TYPE_EXTENSION }
				];
				$scope.statusFilterOptions = [
					{ label: lang.t('All Statuses'), value: 0 }
				];
				
				for(var status in consts.LOG_STATUS_NAMES) {
					$scope.statusFilterOptions.push({ label: consts.LOG_STATUS_NAMES[status], value: status });
					
				}

				$scope.loaders = {
					stop: false,
					delete: false,
					view: false,
					summary: false
				};


				$scope.$watch("filter", function (newVal) {

					$scope.subfilterTitle = '';
					$scope.subfilterOptions = [];
					if(!filterSession) $scope.subfilter = "";
					filterSession = 0;
					if(
						$scope.filter !== consts.LOG_TYPE_BACKUP && 
						$scope.filter !== consts.LOG_TYPE_CLONE && 
						$scope.filter !== consts.LOG_TYPE_BACKUP_ON_DEMAND
					) return;

					switch($scope.filter) {
						case consts.LOG_TYPE_BACKUP:
							$scope.subfilterTitle = 'Backup Job';
							$scope.subfilterOptions.push({ label: lang.t("All Backup Jobs"), value: "" });

							api.listBackupJobs({ 
								data: { list_hidden: true },
								success: function (data) {
									for(var i = 0; i < data.jobs.length; i++) {
										$scope.subfilterOptions.push({ label: data.jobs[i].name, value: data.jobs[i]._id });
									}
								}
							});
						break;
						case consts.LOG_TYPE_CLONE:
							$scope.subfilterTitle = 'Clone Job';
							$scope.subfilterOptions.push({ label: lang.t("All Clone Jobs"), value: "" });

							api.listCloneJobs({
								data: { list_hidden: true },
								success: function (data) {
									for(var i = 0; i < data.jobs.length; i++) {
										$scope.subfilterOptions.push({ label: data.jobs[i].name, value: data.jobs[i]._id });
									}
								}
							});
							break;
					}

				}, true);


				meta = meta.new("logs");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("start_time");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["pid", "type", "start_time", "end_time", "status"]);
				meta.setTotalItems($scope.logs.length);

				$scope.onClickDownload = function(log) {
					window.location = $scope.downloadURL('log_id=' + log._id);
				};

				$scope.onClickDelete = function(log) {

					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("The selected log will be permanently deleted!"),
						confirm: function () {

							api.deleteLog({ 
								data: { _id: [log._id] }, 
								success: function(data, message) {
									$scope.loaders.delete = false;
									$scope.checkall = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.onClickView = function(log) {

					$scope.loaders.view = true;

					api.getLog({ 
						data: { _id: log._id, content: 1 }, 
						success: function (data) {

							$scope.loaders.view = false;
	
							if(!data.content) {
								alert.error(lang.t("No log content found"));
								return;
							}
	
							popup.open({
								size: "lg",
								template: 'logViewer',
								scope: $scope,
								resolve: {
									log: function() { return data; },
									reload: function () { 
										return function(callback) {
											api.getLog({
												data: { _id: log._id, content: 1 },
												success: function (data) {
													if(callback !== undefined) callback(data);
												}
											});
										}
									}
								}
							}).result.then(function() {}, function () {});
						},
						failed: function (message) {
							$scope.loaders.view = false;
							alert.error(message);
						}
					});
				};

				$scope.onClickSummary = function(log) {
					//$scope.loaders.summary = true;

					popup.open({
						size: "lg",
						template: 'logItems',
						scope: $scope,
						resolve: {
							log: function() { return log; }
						}
					}).result.then(function() {}, function () {});
				};


				$scope.checkChanged = function () {

					for(var i = 0; i < $scope.logs.length; i++) {
						if($scope.logs[i].checked && $scope.logs[i].status != consts.LOG_STATUS_PROCESSING) {
							$scope.checked = true;
							return;
						}
					}

					$scope.checked = false;
				};

				$scope.setCheckAll = function() {
					for(var i = 0; i < $scope.logs.length; i++) {
						var log = $scope.logs[i];
						if(log.status != consts.LOG_STATUS_PROCESSING && $scope.permissions[log.type]) log.checked = $scope.checkall;
					}
					$scope.checkChanged();
				};

				$scope.deleteSelected = function() {
					var ids = [];

					for(var i in $scope.logs)
					{
						if($scope.logs[i].checked) ids.push($scope.logs[i]._id);
					}

					if(!ids.length)
					{
						alert.error(lang.t("No log IDs selected"));
						return false;
					}

					confirm.open({
						message: lang.t("The selected logs will be permanently deleted!"),
						confirm: function () {
							api.deleteLog({ 
								data: { _id: ids }, 
								success: function(data, message) {
									$scope.checkall = false;
									$scope.checked = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
						}
					});
				};

				$scope.updateAlert = function(alert) {

					for(var i in $scope.logs) {
						if($scope.logs[i]._id === alert._id) {
							$scope.logs[i] = alert;
							return false;
						}
					}
				};

				$scope.fetch = function() {
					
					$scope.loadingLogs = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					if($scope.filter) apiParams.find.type = $scope.filter;
					if($scope.statusfilter) apiParams.find.status = $scope.statusfilter;

					if($scope.subfilter) {
						switch($scope.filter) {
							case consts.LOG_TYPE_BACKUP: 
							case consts.LOG_TYPE_CLONE: 
								apiParams.find["info.ID"] = $scope.subfilter; 
							break;
						}
					}

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.logs = [];
					$scope.logsProcessingList = [];

					api.listLogs({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.logs);
							$scope.logs = data.logs;
	
							for(var i in $scope.logs) {
								if($scope.logs[i].status === consts.LOG_STATUS_PROCESSING) $scope.logsProcessingList.push($scope.logs[i]);
								$scope.logs[i].information = [];
								for(var a in $scope.logs[i].info) $scope.logs[i].information.push({ key: a, value: $scope.logs[i].info[a] });
								//if(!data[i].information) data[i].information = '-';
							}
							
							checkProcessingStatus();
							
							$scope.loadingLogs = false;
						}
					});
				};

				var checkProcessingStatus = function() {
					
					if($scope.checkTimeout !== undefined || !$scope.logsProcessingList.length) return;
					
					$scope.checkTimeout = setTimeout(function () {

						$scope.checkTimeout = undefined;
						
						var fetch = false, timeout = false, params = {};

						params._id = [];
						for(var i = 0; i < $scope.logsProcessingList.length; i++) 
							params._id.push($scope.logsProcessingList[i]._id);
						
						api.listLogs({ 
							data: params, 
							success: function(data) {
								var logs = data.logs;
								for(var i=0; i < logs.length; i++) {
									if(logs[i].status === consts.LOG_STATUS_PROCESSING) timeout = true;
									else if(logs[i].status !== consts.LOG_STATUS_PROCESSING) fetch = true;
	
									for(var j = 0; j < $scope.logsProcessingList.length; j++) {
										if($scope.logsProcessingList[j]._id != logs[i]._id) continue;
										$scope.logsProcessingList[j].start_time = logs[i].start_time; 
										$scope.logsProcessingList[j].end_time = logs[i].end_time; 
										$scope.logsProcessingList[j].execution_time = logs[i].execution_time; 
									}
								}
	
								if(fetch) $scope.fetch();
								if(timeout) checkProcessingStatus();
							}
						});
					}, 3000);
				};

				$scope.$on("$destroy", function() {
					if($scope.checkTimeout === undefined) return;
					clearTimeout($scope.checkTimeout);
					$scope.checkTimeout = undefined;
				});

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/logViewer',['app'], function(app) {
	app.controller('logViewer',
		["$uibModalInstance", "$scope", "$timeout", "consts", "log", "reload",
			function($uibModalInstance, $scope, $timeout, consts, log, reload) {
				$scope.log = log;
				$scope.log.information = [];
				for(var a in $scope.log.info) $scope.log.information.push({ key: a, value: $scope.log.info[a] });
				
				$scope.autoScroll = true;
				$scope.logContent = null;
				$scope.timeout = null;
				
				$timeout(function () {
					$scope.logContent = document.getElementById('logContent');
					$scope.logContent.scrollTop = $scope.logContent.scrollHeight
					
					$scope.logContent.addEventListener('scroll', function () {
						$scope.autoScroll = Math.abs($scope.logContent.scrollHeight - $scope.logContent.scrollTop - $scope.logContent.clientHeight) < 1;
					});
				});

				$scope.reloadLog = function () {
					$scope.timeout = null;

					reload(function(data) {
						$scope.log = data;

						$timeout(function () {
							if ($scope.autoScroll && $scope.logContent) $scope.logContent.scrollTop = $scope.logContent.scrollHeight;
						});

						if($scope.log.status == consts.LOG_STATUS_PROCESSING) $scope.timeout = setTimeout($scope.reloadLog, 2000);
					});
				}

				if($scope.log.status == consts.LOG_STATUS_PROCESSING) $scope.reloadLog();

				$scope.ok = function () { $uibModalInstance.close(); };
				
				$scope.$on('$destroy', function () {
					if($scope.timeout) clearTimeout($scope.timeout);
					$scope.timeout = null;
				});
			}
		]
	);
});


define('controllers/logItems',['app'], function(app) {
	app.controller('logItems',
		["$uibModalInstance", "$scope", "$timeout", "lang", "meta", "consts", "api", "alert", "log", "popup",
			function($uibModalInstance, $scope, $timeout, lang, meta, consts, api, alert, log, popup) {

				$scope.log = log;
				$scope.items = [];
				$scope.loadingItems = false;

				$scope.loaders = {
					view: false
				};

				meta = meta.new("log_items");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("priority");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["priority","started","ended","execution_time","owner","status"]);
				meta.setTotalItems($scope.items.length);
				meta.setPageSizes([5,10]);
				meta.setPageSize(5);
				meta.setLimit(5);
				
				$scope.downloadLogItem = function(item) {
					window.location = $scope.downloadURL('log_id=' + $scope.log._id + ':' + item._id);
				};
				
				$scope.viewLogItem = function(item) {
					$scope.loaders.view = true;

					api.getLogItem({ 
						data: { _id: item._id, log_id: $scope.log._id, content: 1 }, 
						success: function (data) {

							$scope.loaders.view = false;

							if(!data.content) {
								alert.error(lang.t("No log content found"));
								return;
							}
	
							popup.open({
								size: "lg",
								template: 'logViewer',
								scope: $scope,
								resolve: {
									log: function() {
	
										var info = {};
										if(data.data.account) info.account = data.data.account;
										info.priority = data.priority;
										//info.owner = response.data.owner_name + " (#" + response.data.owner + ")";
										info.created = lang.d(data.created);
										//info.message = response.data.message;
	
										return {
											_id: data._id,
											type: data.type,
											file: data.file,
											content: data.content,
											start_time: data.started,
											end_time: data.ended,
											execution_time: data.execution_time,
											status: consts.QUEUE_STATUS_TO_LOG[data.status] === undefined ? consts.LOG_STATUS_PROCESSING : consts.QUEUE_STATUS_TO_LOG[data.status],
											info: info
										};
									},
									reload: function () {
										return function(callback) {
											api.getLogItem({
												data: { _id: item._id, log_id: $scope.log._id, content: 1 },
												success: function (data) {

													var info = {};
													if(data.data.account) info.account = data.data.account;
													info.priority = data.priority;
													//info.owner = response.data.owner_name + " (#" + response.data.owner + ")";
													info.created = lang.d(data.created);
													//info.message = response.data.message;

													if(callback !== undefined) callback({
														_id: data._id,
														type: data.type,
														file: data.file,
														content: data.content,
														start_time: data.started,
														end_time: data.ended,
														execution_time: data.execution_time,
														status: consts.QUEUE_STATUS_TO_LOG[data.status] === undefined ? consts.LOG_STATUS_PROCESSING : consts.QUEUE_STATUS_TO_LOG[data.status],
														info: info
													});
												}
											});
										}
									}
								}
							}).result.then(function() {}, function () {}); 
						},
						failed: function (message) {
							$scope.loaders.view = false;
							alert.error(message);
						}
					});
				};
				
				$scope.fetch = function() {

					$scope.loadingItems = true;

					var apiParams = {
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						sort: {},
						filter: meta.getFilter(),
						"log_id": $scope.log._id
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.items = [];

					api.listLogItems({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.items);
							$scope.items = data.items;
							$scope.loadingItems = false;
						},
						failed: function (message) {
							alert.error(message);
							$uibModalInstance.close();
						}
					});
				};

				$timeout($scope.fetch);

				$scope.close = function () { $uibModalInstance.close(); };
	}]);

});


define('controllers/settings',['app'], function(app) {
	app.controller("settings",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "meta", "confirm", "util", "permissions", "cfpLoadingBar", "lang", "alert",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, meta, confirm, util, permissions, cfpLoadingBar, lang, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.saveing = false;
				$scope.changed = false;
				$scope.loading = false;
				$scope.sectionChanged = false;
				$rootScope.noSaveButton = false;

				$scope.details = {};
				$scope.saveData = {};

				$scope.sections = [
					{ _id: 'general', 		name: lang.t('General'), 		 	template: 'general', 		icon: 'fa-cogs', 		docs:'/Settings/general.html' },
					{ _id: 'performance', 	name: lang.t('Performance'), 	 	template: 'performance',	icon: 'fa-sliders-h',  	docs:'/Settings/performance.html' },
					{ _id: 'resource', 		name: lang.t('Resource'), 		 	template: 'resource', 		icon: 'fa-microchip', 	docs:'/Settings/resource.html' },
					{ _id: 'restore', 		name: lang.t('Restore'), 		 	template: 'restore', 		icon: 'fa-sync', 		docs:'/Settings/restore.html' },
					{ _id: 'privacy', 		name: lang.t('Privacy & Security'), template: 'privacy', 		icon: 'fa-lock', 		docs:'/Settings/privacyAndSecurity.html' },
					{ _id: 'panel', 		name: lang.t('Panel'), 				template: 'panel', 			icon: 'fa-solar-panel', docs:'/Settings/Panel.html' },
					{ _id: 'snapshots',		name: lang.t('Backup on Demand'), 	template: 'snapshots', 		icon: 'fa-cubes', 		docs:'/Settings/snapshots.html' },
					{ _id: 'notification', 	name: lang.t('Notification'), 	 	template: 'notification', 	icon: 'fa-bell', 		docs:'/Settings/notification.html' },
					{ _id: 'update', 		name: lang.t('Update Preferences'),	template: 'update', 		icon: 'fa-list', 	docs:'/Settings/update.html' },
					{ _id: 'binary', 		name: lang.t('Binary Locations'), 	template: 'binary', 		icon: 'fa-terminal', 	docs:'/Settings/binaryLocations.html'  }
				];

				$scope.getSection = function (section_id) {
					for(var i = 0; i < $scope.sections.length; i++) {
						if($scope.sections[i]._id === section_id) {
							return $scope.sections[i];
						}
					}

					return $scope.sections[0];
				};

				$scope.changeSection = function (section) {

					if(!$scope.changed) {
						$location.path('/settings/' + section._id);
						return;
					}

					$scope.sectionChanged = true;
					
					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirm: function () {},
						cancel: function () { $location.path('/settings/' + section._id); },
						cancelLabel: lang.t("Leave Section"),
						confirmLabel: lang.t("Stay On Section"),
					});
				};

				$scope.validateOptions = {};
				$scope.$on('validateOptions', function (e, data) {
					$scope.validateOptions = data;
				});

				$scope.$on('$destroy', function() {
					if(!$scope.changed) return;
					if($scope.sectionChanged) {
						$scope.sectionChanged = false;
						return;
					}

					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirmLabel: lang.t("Save"),
						cancelLabel: lang.t("Disregard Changes"),
						confirm: $scope.saveChanges
					});
				});

				$scope.loadSection = function (section) {
					$scope.currentSection = section;
					
					if(section._id === 'panel') {
						$scope.settingsSection = '';
						app.registerController(
						'panelSettings',
						'plugins/panel',
						function(path) {
							$scope.settingsSection = $scope.includePath('panel/view', 'plugins');
						});
					} else {
						$scope.settingsSection = $scope.includePath('settings/' + section.template);
					}
				};

				$scope.loadSection($scope.getSection($routeParams.section ? $routeParams.section : 'general'));

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details);
				}, true);

				$scope.$on('noSaveButtonChange', function (event, value) {
					$scope.noSaveButton = value;
				});
				
				$scope.saveChanges = function(callback) {
					cfpLoadingBar.start();

					if($scope.saveing) return;

					$scope.saveing = true;

					for (var key in $scope.saveData.options) {
						if($scope.validateOptions[key] === undefined) continue;

						if(!$scope.validateOptions[key].validation($scope.saveData.options[key])) {
							alert.error(lang.t("Invalid value provided for %s", $scope.validateOptions[key].name));
							cfpLoadingBar.complete();
							$scope.saveing = false;
							return;
						}
					}

					var apiParams = util.saveParams($scope.saveData, $scope.details, undefined, function (key) {
						return key == 'mustagree' || key == 'suspendbackups';
					});
					apiParams.section = $scope.currentSection._id;
					
					api.manageSettings({ 
						data: apiParams,
						success: function(data, message) {
							$scope.saveing = false;
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(callback !== undefined) callback();
							
							if(apiParams.section === 'snapshots') {
								$rootScope.info.bod_disabled = !data.backup; 
							}

							$scope.$broadcast('saveChanges', {
								success: true,
								message: message,
								data: data
							});
							
							alert.success(message);
						},
						failed: function(message) {
							$scope.saveing = false;

							$scope.$broadcast('saveChanges', {
								success: false,
								message: message
							});

							alert.error(message);
						}
					});
				};

				$scope.fetch = function() {
					$scope.loading = true;
					api.getSettings({ 
						data: { section: $scope.currentSection._id }, 
						success: function(data) {
							$scope.loading = false;
							$scope.details = {};
							$scope.saveData = {};
							
							if(util.countObj(data)) {
								$scope.details = data;
								$scope.saveData = util.duplicateObject($scope.details);
							}
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$timeout($scope.fetch);

			}]);
});


define('controllers/settings/binary',['app'], function(app) {
	app.controller("binarySettings", ["$rootScope", "$scope",
		function ($rootScope, $scope) {
			$scope.$on('saveChanges', function (event, data) {
				for(var key in data.data) $scope.saveData[key] = data.data[key]; 
			});

		}
	]);
});



define('controllers/settings/general',['app'], function(app) {
	app.controller("generalSettings", ["$rootScope", "$scope", "api", "lang",
		function ($rootScope, $scope, api, lang) {
			$scope.time_formats = [
				{ value: 12, label: lang.t('12 hours based (e.g. 11:00 PM)') },
				{ value: 24, label: lang.t('24 hours based (e.g. 23:00)') }
			];
			
			$scope.email_integrations = [
				{ value: '', label: '- ' + lang.t('Disabled') + ' -' },
			];
			
			api.listNotificationIntegrations({
				data: { find: { type: 'Email' } },
				success: function (data) {
					for(var i = 0; i < data.notifications.length; i++) {
						$scope.email_integrations.push({ value: data.notifications[i]._id, label: data.notifications[i].name });
					}

				}
			});
			
			$scope.$on('saveChanges', function (event, data) {
				window.PAGE.timeformat = data.data.time_format;
			});
		}
	]);
});



define('controllers/settings/notification',['app'], function(app) {
	app.controller("notificationSettings",
		["$rootScope", "$scope", "$timeout", "lang", "consts", "api", "confirm", "alert", "meta",
			function ($rootScope, $scope, $timeout, lang, consts, api, confirm, alert, meta) {

				$scope.loadingNotifications = false;
				$scope.notifications = [];
				$scope.filter = '';
				$scope.filterOptions = [{ label: lang.t('All Notifications'), value: '' }];
				$scope.saveing = false;

				$scope.loaders = {
					state: false,
					delete: false
				};

				meta = meta.new("notifications");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("asc");
				meta.setSortFields(["name","type","owner","disabled"]);
				meta.setTotalItems($scope.notifications.length);

				$scope.onClickDelete = function(notification) {

					if($scope.saveing) return;
					
					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This notification will be permanently deleted!"),
						confirm: function () {
							api.deleteNotificationIntegration({
								data: { _id: notification._id },
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};
				
				$scope.toggleStatus = function(notification) {
					if($scope.saveing) return;
					$scope.saveing = true;

					$scope.loaders.state = true;
					var disabled = !notification.disabled;

					api.manageNotificationIntegration({
						data: {
							_id: notification._id,
							action: 'modify',
							disabled: disabled
						},
						success: function(data, message) {
							$scope.saveing = false;
							$scope.loaders.state = false;
							notification.disabled = disabled;
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;
							$scope.loaders.state = false;
							alert.error(message);
						}
					});
				};

				$scope.listNotifications = function(callback) {
					if(callback === undefined || typeof callback != 'function') callback = function(){};

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					if($scope.filter) apiParams.find.type = $scope.filter;
					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listNotificationIntegrations({
						data: apiParams,
						success: function (data, message) { callback({ success: true, data: data, message: message}); },
						failed: function (data, message) { callback({ success: false, data: data, message: message}); }
					});
				};

				$scope.fetch = function() {
					if($scope.loadingNotifications) return;
					$scope.loadingNotifications = true;
					$scope.listNotifications(function (response) {
						$scope.notifications = response.data.notifications;
						$scope.loadingNotifications = false;
						meta.setTotalItems(response.data.total);
						meta.calculate($scope.notifications);
					});
				};

				api.listNotificationIntegrationTypes({
					success: function (data) {
						$scope.types = data;
						for(var i = 0; i < data.types.length; i++) {
							$scope.filterOptions.push({ label: data.types[i].name, value: data.types[i].key });
						}
					}
				});

				$timeout($scope.fetch);
			}]);
});


define('controllers/settings/notificationManage',['app'], function(app) {
	app.controller("notificationManage",
		["$rootScope", "$scope", "$routeParams", "$q", "$location", "$timeout", "api", "meta", "util", "confirm", "permissions", "lang", "consts", "alert",
			function ($rootScope, $scope, $routeParams, $q, $location, $timeout, api, meta, util, confirm, permissions, lang, consts, alert) {
				$rootScope.$emit('menuItem', 'Settings');

				$scope.details = {
					type: '',
					frequency: {},
					owner: $scope.loggedAccount._id,
					owner_name: $scope.loggedAccount.username,
					options: {}
				};

				$scope.saveData = util.duplicateObject($scope.details);
				$scope.autocomplete = { accountText: $scope.saveData.owner_name };
				
				$scope.saveing = false;
				$scope.sending = false;
				$scope.changed = true;
				$scope.cancelled = false;
				$scope.types = [];
				$scope.plugin = {};
				$scope.plugin_available = {};
				$scope.plugins_available = {};
				$scope.installing = false;
				
				$scope.frequencies = [
					{ value: 0, label: lang.t("Frequency") + " - " + lang.t("Disabled") },
					{ value: consts.NOTIFICATION_FREQUENCY_REALTIME, label: lang.t("Frequency") + " - " + lang.t("Real Time") },
					{ value: consts.NOTIFICATION_FREQUENCY_ONCEADAY, label: lang.t("Frequency") + " - " + lang.t("Once a Day") }
				];
				
				$scope.resetFrequency = function() {
					if($scope.saveData.frequency[consts.ALERT_LEVEL_INFO] === undefined) $scope.saveData.frequency[consts.ALERT_LEVEL_INFO] = consts.NOTIFICATION_FREQUENCY_REALTIME;
					if($scope.saveData.frequency[consts.ALERT_LEVEL_WARNING] === undefined) $scope.saveData.frequency[consts.ALERT_LEVEL_WARNING] = consts.NOTIFICATION_FREQUENCY_REALTIME;
					if($scope.saveData.frequency[consts.ALERT_LEVEL_CRITICAL] === undefined) $scope.saveData.frequency[consts.ALERT_LEVEL_CRITICAL] = consts.NOTIFICATION_FREQUENCY_REALTIME;
				};

				$scope.resetFrequency();
				
				$scope.isAvailableNotificationIntegration = function() {
					return $scope.saveData.type && $scope.saveData.type.indexOf('AvailableNotificationIntegrations') >= 0;
				};

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.saveData.owner = account._id;
					$scope.saveData.owner_name = account.username;
					$scope.autocomplete.accountText = account.username;
					var activeElement = document.activeElement;
					if (activeElement) activeElement.blur();
				};

				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.resetOptions = function () {
					$scope.options = {};
				};
				
				$scope.loadTemplate = function(type) {
					if(!type) return;

					if(type.indexOf('::') >= 0) {
						var parts = type.split('::');
						type = parts[0];
						$scope.plugin_available = $scope.plugins_available[parts[1]];
					}

					$scope.resetOptions();

					switch(type) {
						case 'AvailableNotificationIntegrations':
							$scope.notificationIntegrationType = $scope.includePath('notifications/' + type);
							$scope.experimental = $scope.plugin_available.experimental !== undefined ? $scope.plugin_available.experimental : '';
						break;

						default:
							if($scope.plugin[type] === undefined) return;
							lang.setDefaultNS('plugins-notification-' + type);
							app.registerPluginController($scope.plugin[type], function(path) {
								$scope.publicDir = path;
								$scope.notificationIntegrationType = $scope.publicDir + '/view.htm?v=' + $scope.plugin[type].version;
								$scope.experimental = $scope.plugin[type].experimental;
							});
						break;
					}
				};

				$scope.loadNotificationIntegrationType = function() {
					$scope.loadTemplate($scope.saveData.type);
				};

				$scope.resetOptions();

				$scope.$on('options', function (event, options) {
					for(var key in options) $scope.options[key] = options[key];
				});

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('$destroy', function() {
					if(!$scope.changed || $scope.cancelled) return;

					confirm.open({
						message: lang.t("You didn't saved your changes"),
						confirm: $scope.saveChanges,
						cancelLabel: lang.t("Disregard Changes"),
						confirmLabel: lang.t("Save"),
					});
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/settings/notification');
				};

				$scope.sendTest = function () {

					if(!$scope.details._id) {
						alert.error(lang.t("You can't send test message on unconfigured notification integration"));
						return;
					}
					
					if($scope.sending) return;
					$scope.sending = true;

					api.sendNotificationIntegrationTest({
						data: { _id: $scope.details._id },
						success: function(data, message) {
							$scope.sending = false;
							alert.success(message);
						},
						failed: function (message) {
							$scope.sending = false;
							alert.error(message);
						}
					});

				};
				
				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function(key) {
						return ($scope.details._id === undefined && key === 'type');
					});

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageNotificationIntegration({ 
						data: apiParams, 
						success: function(data, message) {
							$scope.saveing = false;
							$scope.details = data;
							$scope.saveData = util.duplicateObject($scope.details);
							$scope.changed = false;
	
							if(callback === undefined) {
								if(apply) $location.path('/settings/notification/manage/' + data._id);
								else $location.path('/settings/notification');
								alert.success(message);
							}

							if(callback !== undefined && typeof callback === 'function') callback();

						},
						failed: function (message) {
							$scope.saveing = false;
							alert.error(message);
							if(callback !== undefined && typeof callback === 'function') callback();
						}
					});
				};

				$scope.installNotificationIntegration = function() {

					if($scope.installing) return;
					$scope.installing = true;

					confirm.open({
						message: lang.t("This notification integration will be installed on this server!"),
						confirm: function () {
							api.installPlugin({ 
								data: { package_id: $scope.plugin_available._id, disabled: 0 }, 
								success: function (data, message) {
									$scope.installing = false;

									//$scope.installed_plugin = data;
									$scope.plugin_available = {};
	
									$scope.loadNotificationIntegrations(function () {
										$scope.saveData.type = data.code;
										$scope.loadNotificationIntegrationType();
										alert.success(message);
									});
								},
								failed: function (message) {
									$scope.installing = false;
									alert.error(message);
								}
							});
						},
						cancel: function () {
							$scope.installing = false;
						}
					});
				};

				$scope.loadNotificationIntegrations = function(callback) {

					if(callback === undefined || typeof callback !== 'function') callback = function(){};

					$scope.types = [];
					$scope.plugins_available = {};

					api.listNotificationIntegrationTypes({ 
						success: function (data) {

							for(var i = 0; i < data.types.length; i++) {
	
								var type = data.types[i];
	
								$scope.types.push({ label: type.name, value: type.key, group: lang.t('Installed Integrations') });
								$scope.plugin[type.key] = {
									type: consts.PLUGIN_TYPE_NOTIFICATION,
									code: type.key,
									version: type.version
								};
	
								if(!$scope.details.type && !$routeParams.id) {
									$scope.details.type = type.key;
									$scope.saveData.type = type.key;
									$scope.loadNotificationIntegrationType();
								}
							}
	
							api.listPackagesAvailable({ 
								data: { find: { type: consts.PLUGIN_TYPE_NOTIFICATION } }, 
								success: function(data) {
									for(var i = 0; i < data.packages.length; i++) {
										var pkg = data.packages[i];
										$scope.plugins_available[pkg.code] = pkg;
										$scope.types.push({ label: lang.t("%s via %s", pkg.name, pkg.repo_name), value: "AvailableNotificationIntegrations::" + pkg.code, group: lang.t('Available Integrations') });
									}
		
									callback();
								},
								failed: function () {
									callback();
								}
							});
						}
					});
				};


				$scope.loadNotificationIntegrations(function () {
					if($routeParams.id) {
						api.getNotificationIntegration({ 
							data: { _id: $routeParams.id }, 
							success: function(data) {
								$scope.details = data;
	
								if({}.toString.apply($scope.details.options) !== '[object Object]') {
									$scope.details.options = {};
								}
	
								$scope.saveData = util.duplicateObject($scope.details);
								$scope.autocomplete.accountText = $scope.saveData.owner_name;
								//delete $scope.details.options;
								$scope.loadNotificationIntegrationType();
							}
						});
					}
				});

			}]);
});


define('controllers/settings/performance',['app'], function(app) {
	app.controller("performanceSettings",
		["$rootScope", "$scope", "api", "lang",
			function ($rootScope, $scope, api, lang) {

				$scope.queuePriorities = [
					{ _id: '', name: lang.t('Default') }
				];

				$scope.fetchQueuePriorities = function() {
					api.listQueuePriorities({ 
						success: function (data) {
							var priorities = data.priorities;
							for(var i=0; i< priorities.length; i++ ){
								$scope.queuePriorities.push({ _id: priorities[i]._id, name: priorities[i].name });
							}
						}
					});
				};
				$scope.fetchQueuePriorities();


				$scope.mysqlpackets_options = [
					{ label: lang.t("Default"), value: 0 },
					{ label: "32 MB", value: 32 },
					{ label: "64 MB", value: 64 },
					{ label: "128 MB", value: 128 },
					{ label: "256 MB", value: 256 },
					{ label: "512 MB", value: 512 },
					{ label: "1 GB", value: 1024 }
				];

				$scope.gtidpurged_options = [
					{ label: lang.t("Default"), value: "" },
					{ label: "Auto", value: "AUTO" },
					{ label: "Off", value: "OFF" },
					{ label: "On", value: "ON" },
					{ label: "Commented", value: "COMMENTED" }
				];
			}]);
});


define('controllers/settings/resource',['app'], function(app) {
	app.controller("resourceSettings", ["$rootScope", "$scope", "lang",
			function ($rootScope, $scope, lang) {
	}]);
});


define('controllers/settings/privacy',['app'], function(app) {
	app.controller("privacySettings",
		["$rootScope", "$scope", "confirm", "lang", "api",
			function ($rootScope, $scope, confirm, lang, api) {

				$scope.encryption_key = '';
				api.getMasterEncryptionKey({ 
					success: function (data) {
						$scope.encryption_key = data.encryption_key;
					}
				});

				$scope.$watch('saveData.encryption_selection', function () {

					if(
						$scope.details.encryption_selection === undefined ||
						$scope.details.encryption_selection == 0 ||
						$scope.saveData.encryption_selection === undefined ||
						$scope.saveData.encryption_selection == 1
					) return;

					confirm.open({
						message: lang.t("WARNING! All encrypted backups for accounts that are using *remote* encryption key will be deleted and lost forever!"),
						confirmLabel: lang.t("OK, I understand the risks"),
						confirm: function () {
							$scope.saveData.condition = 1;
						},
						cancel: function () {
							$scope.saveData.condition = 0;
							$scope.saveData.encryption_selection = 1;
						}
					});
				});
			}
		]
	);
});


define('controllers/settings/restore',['app'], function(app) {
	app.controller("restoreSettings",
		["$rootScope", "$scope", "$timeout", "api", "consts", "lang",
			function ($rootScope, $scope, $timeout, api, consts, lang) {
				$scope.ownership_types = ['nobody','user'];

				/*
				$scope.destinations = [{_id: '', name: lang.t('- Disable Safety Backups -') }];

				$scope.fetchDestinations = function() {
					api.listDestinations({}, function(response) {
						for(var i = 0; i < response.data.destinations.length; i++) {

							if(
								response.data.destinations[i].clone_destination ||
								response.data.destinations[i].engine != consts.DESTINATION_ENGINE_JETBACKUP ||
								!response.data.destinations[i].incremental_ability

							) continue;

							$scope.destinations.push(response.data.destinations[i]);
						}
					});
				};

				$timeout($scope.fetchDestinations());

				 */
			}
		]
	);
});


define('controllers/settings/snapshots',['app'], function(app) {
	app.controller("snapshotsSettings",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "lang", "consts",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, lang, consts) {

				$scope.backups = [{_id: '', name: lang.t('- Disable Backup on Demand System -') }];
				$scope.sizes = ['MB','GB','TB'];

				$scope.fetchBackupJobs = function() {
					var params = {find:{}};
					params.find.type = consts.BACKUP_TYPE_ACCOUNT;
					params.find.contains = consts.BACKUP_TYPE_ACCOUNT_FULL;
					api.listBackupJobs({ 
						data: params, 
						success: function(data) {
							for(var i = 0; i < data.jobs.length; i++) $scope.backups.push(data.jobs[i]);
						}
					});
				};

				$timeout($scope.fetchBackupJobs());

	}]);
});


define('controllers/settings/update',['app'], function(app) {
	app.controller("updateSettings",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "lang", "consts",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, lang, consts) {

				$scope.tiers = [
					{ key: "release", name: "RELEASE", description: lang.t("Receives well-tested updates directly from the JetApps repository, ensuring optimal reliability and minimal risk. Ideal for production environments where stability and consistency is paramount.") },
					{ key: "rc", name: "RELEASE CANDIDATE (RC)", description: lang.t("Pre-release versions that are close to the final stable release, with updates from our repository servers. These versions are intended for final testing before the official release. Recommended for users who wish to test the upcoming stable version and provide feedback.") },
					{ key: "edge", name: "EDGE", description: lang.t("Cutting-edge updates with the latest features and improvements, provided from our repository servers. Should be more stable than ALPHA but still may contain bugs or other issues. Great for users who prefer to stay at the forefront of development.") },
					{ key: "alpha", name: "ALPHA", description: lang.t("Early access to features still in development, sourced from our repository servers. Expect frequent updates and potential instability. Suitable for developers and testers who want to explore new features.") },
				];
				
				$scope.getVersion = function (tier) {
					if($scope.saveData.versions === undefined || $scope.saveData.versions[tier] === undefined) return '';
					return $scope.saveData.versions[tier];
				};

				$scope.$on('saveChanges', function (event, data) {
					$rootScope.info.tier = data.data.tier.toUpperCase();
				});
	}]);
});


define('controllers/fileManager',['app'], function(app) {

		app.controller("fileManager",
			["$rootScope", "$scope", "$interval", "$timeout", "api", "meta", "$window", "$routeParams", "$location", "permissions", "consts", "lang", "alert", "pathManager",
				function($rootScope, $scope, $interval, $timeout, api, meta, $window, $routeParams, $location, permissions, consts, lang, alert, pathManager) {
					$rootScope.$emit('menuItem', 'BackupManager');

					$scope.manager = pathManager.new($scope.listPathes !== undefined ? $scope.listPathes : []);

					$scope.type = $routeParams.type;
					$scope.typeId = $routeParams.id;
					$scope.typeDetails = { name: '' };
					$scope.files = [];
					$scope.loadingFiles = false;
					$scope.currentPath = '';
					$scope.breadcrumbs = [];
					$scope.filesIndex = {};
					$scope.actionModule = undefined;
					//$scope.config = {};
					$scope.backup_type = 2;
					$scope.restoringBackup = false;
					$scope.downloadingBackup = false;
					$scope.downloads = [];
					$scope.restores = [];
					$scope.downloadsTmp = [];
					$scope.queues = [];
					$scope.isDirectories = false;
					$scope.showhidden = true;
					$scope.checkedAll = false;

					var statusInterval;

					$scope.clearStatus = function() {
					};

					$scope.cancelAction = function() {
						$scope.actionModule = undefined;
					};

					$scope.changeView = function(view){
						$location.path(view); // path not hash
					};

					$scope.onClickRestore = function() {
						var selected = getSelected();

						if(!selected.length) {
							alert.error("Please select files to restore");
							return;
						}

						$scope.actionModule = ($scope.actionModule === 'restore') ? undefined : 'restore';
					};

					/*
					$scope.onClickRestoreConfirm = function() {

						$scope.restoringBackup = true;

						var apiParams = {};
						apiParams['_id'] = $scope.typeId;
						apiParams['files'] = getSelected();

						api.addQueueItems({ 
							data: apiParams, 
							success: function(data, message) {

								$scope.queues.push(data._id);
	
								$scope.restoringBackup = false;
								$scope.actionModule = undefined;
								$scope.uncheckAll();
								$scope.getRestores();
	
								alert.success(message);
								return true;
							},
							failed: function (message) {
								alert.error(message);
								$scope.restoringBackup = false;
							}
						});
					};
					*/

					$scope.onClickDownload = function() {

						var selected = getSelected();

						if(!selected.length) {
							alert.error("Please select files to download");
							return;
						}

						$scope.actionModule = ($scope.actionModule === 'download') ? undefined : 'download';
					};

					/*
					$scope.onClickDownloadConfirm = function() {

						$scope.downloadingBackup = true;

						var apiParams = {};
						apiParams._id = $scope.typeId;
						apiParams.type = $scope.type;
						apiParams.files = getSelected();

						api.addQueueDownload(apiParams, function(response) {

							if(!response.success) {
								alert.error(response.message);
								$scope.downloadingBackup = false;
								return false;
							}

							$scope.queues.push(response.data._id);

							$scope.downloadingBackup = false;
							$scope.actionModule = undefined;
							$scope.uncheckAll();
							$scope.getDownloads();

							alert.success(response.message);
							return true;
						});
					};
					*/

					
					/*
					$scope.isConditionsAgreed = function() {

						for(var i in $scope.config.restore_conditions)
						{
							if($scope.config.restore_conditions[i].type !== 0 && $scope.config.restore_conditions[i].type !== $scope.backup_type) continue;
							if(!$scope.config.restore_conditions[i].checked) return true
						}

						return false;
					};
					*/

					var getSelected = function() {

						var selected = [];

						for(var i in $scope.filesIndex)
						{
							for(var j in $scope.filesIndex[i].files)
							{
								if($scope.filesIndex[i].files[j] != null && $scope.filesIndex[i].files[j].checked !== undefined && $scope.filesIndex[i].files[j].checked)
								{
									selected.push($scope.filesIndex[i].files[j].path);
								}
							}
						}

						return selected;
					};

					$scope.canPerformAction = function () {

						for(var i in $scope.filesIndex)
						{
							for(var j in $scope.filesIndex[i].files)
							{
								if($scope.filesIndex[i].files[j] != null && $scope.filesIndex[i].files[j].checked !== undefined && $scope.filesIndex[i].files[j].checked)
								{
									return false;
								}
							}
						}

						return true;
					};

					$scope.emitSelected = function() {
						var output = {};
						var selected = $scope.manager.getSelected();

						for(var i = 0; i < selected.length; i++) {
							var path = selected[i];
							var name = path.replace(/.*\//, '');
							var parent = path.match(/.*\//).join('');
							if(parent !== '/') parent = parent.replace(/\/$/, '');

							if($scope.filesIndex[parent] === undefined) {
								output[path] = {empty:true};
								continue;
							}

							var files = $scope.filesIndex[parent].files;
							for(var j = 0; j < files.length; j++) {
								if(files[j].name !== name) continue;
								output[path] = files[j];
								break;
							}
						}

						$rootScope.$emit('filesChanged', output);
					};

					$scope.toggleFile = function(file) {
						if($scope.manager.isExists(file.path)) $scope.manager.removePath(file.path);
						else $scope.manager.addPath(file.path);
						$scope.emitSelected();
						$scope.calculateCheckedAll();
					};

					$scope.isDisabled = function(file) {
						return $scope.manager.isChildren(file.path);
					};

					$scope.isChecked = function(file) {
						file.checked = ($scope.manager.isExists(file.path) || $scope.manager.isChildren(file.path));
						return file.checked;
					};

					$scope.isChildrenChecked = function(file) {
						return $scope.manager.isParent(file.path);
					};

					var manageBreadcrumbs = function(file) {
						if(file.path === '/') file.name = '/' + $scope.type + '-root';
						$scope.breadcrumbs.unshift(file);
						if(file.parent !== undefined) manageBreadcrumbs(file.parent);
					};

					var handleResponse = function(data, file) {
						$scope.filesIndex[file.path] = data;

						$scope.files = data.files;

						/*
						$scope.files.sort(function(a, b){
							if(a.type == 'Directory' && b.type != 'Directory') return -1;
							if(b.type == 'Directory' && a.type != 'Directory') return 1;
							return a.name < b.name ? -1 : 1;
						});
						
						 */

						$scope.loadingFiles = false;
					};

					$scope.toggleHidden = function() {
						$scope.showhidden = !$scope.showhidden;
						$scope.calculateCheckedAll();
					};

					var metaFiles = meta.new("file_manager");
					$scope.meta = metaFiles;
					$scope.metaData = metaFiles.getData();

					if(!metaFiles.getSortBy()) metaFiles.setSortBy("type");
					if(!metaFiles.getSortDirection()) metaFiles.setSortDirection("asc");
					metaFiles.setSortFields(["name","type","size","created"]);
					metaFiles.setPageSize(50);
					metaFiles.setPageSizes([10,25,50,100]);
					metaFiles.setTotalItems($scope.files.length);

					$scope.currentFile = undefined;
					
					$scope.fetch = function(file, resetPagination) {

						if(file === undefined) file = $scope.currentFile;
						else $scope.currentFile = file;

						if(file.path === undefined) file.path = '/';

						$scope.loadingFiles = true;
						$scope.files = [];

						$scope.breadcrumbs = [];
						manageBreadcrumbs(file);

						if(resetPagination) metaFiles.setCurrentPage(1);

						//if($scope.filesIndex[file.path] !== undefined) {
						//	handleResponse($scope.filesIndex[file.path], file);
						//	return;
						//}

						var apiParams = {
							sort: {},
							skip: metaFiles.getSkip(),
							limit: metaFiles.getPageSize(),
							find: {},
							filter: ''
						};

						apiParams._id = $scope.typeId;
						apiParams.type = $scope.type;
						apiParams.path = file.path;
						apiParams.file_id = file.id;
						apiParams.sort[metaFiles.getSortBy()] = metaFiles.getSortDirectionInt();

						api.fileManager({ 
							data: apiParams,
							success: function(data) {
								for(var i = 0; i < data.files.length; i++) {
									data.files[i].path = file.path + (file.path === '/' ? '' : '/') + data.files[i].name;
									data.files[i].parent = file;
									data.files[i].hidden = data.files[i].name.substr(0, 1) === '.';
								}

								metaFiles.setTotalItems(data.total);
								metaFiles.calculate(data.files);
								handleResponse(data, file);
								$scope.calculateCheckedAll();
							},
							failed: function (message) {
								alert.error(message);
							}
						});

					};

					$scope.hideCheckAll = function() {
						return $scope.manager.isExists($scope.currentFile.path) || $scope.manager.isChildren($scope.currentFile.path);
					};
					
					$scope.calculateCheckedAll = function () {

						for(var i = 0; i < $scope.files.length; i++) {
							var file = $scope.files[i];
							if(
								!(file.type === 'File' || file.type === 'Directory') ||
								(file.hidden && !$scope.showhidden && $scope.checkedAll)
							) continue;

							var exists = $scope.manager.isExists(file.path);
							if(!exists) {
								$scope.checkedAll = false;
								return;
							} 
						}

						$scope.checkedAll = true;
					};
					
					$scope.toggleCheckAll = function() {
						$scope.checkedAll = !$scope.checkedAll;
						
						for(var i = 0; i < $scope.files.length; i++) {
							var file = $scope.files[i];
							if(
								!(file.type === 'File' || file.type === 'Directory') ||
								(file.hidden && !$scope.showhidden && $scope.checkedAll)
							) continue;

							var exists = $scope.manager.isExists(file.path);
							
							if($scope.checkedAll && !exists) $scope.manager.addPath(file.path);
							else if(!$scope.checkedAll && exists) $scope.manager.removePath(file.path);
						}

						$scope.emitSelected();
					};

					$scope.uncheckAll = function () {

						for(var i in $scope.filesIndex)
						{
							for(var j in $scope.filesIndex[i].files)
							{
								if($scope.filesIndex[i].files[j] != null && $scope.filesIndex[i].files[j].checked !== undefined && $scope.filesIndex[i].files[j].checked)
								{
									$scope.filesIndex[i].files[j].checked = false;
								}
							}
						}

					};

					$scope.directDownload = function(download) {
						window.location = $scope.downloadURL('download_id=' + download.download_id);
					};

					/*
					$scope.getDownloads = function () {
						$scope.downloads = [];
						$scope.loadingDownloads = true;

						var apiParams = {};
						apiParams._id = $scope.typeId;
						apiParams.type = $scope.type;

						api.getBackupDownloads(apiParams, function(response) {

							if (!response.success) {
								$scope.downloads = [];
								alert.error(response.message);
								$scope.loadingDownloads = false;
								return false;
							}

							for(var i = 0; i < response.data.downloads.length; i++) {
								$scope.downloads.push(response.data.downloads[i]);
								if ($scope.downloads[i].ready) $scope.downloads[i].status = 100;
								else $scope.downloads[i].status = 1;
							}
							var find = {status:{'$gt':100}};
							api.listQueueItems({ type: consts.QUEUE_TYPE_DOWNLOAD, snap_item_id: $scope.typeId, find: find }, function(response) {

								if(!response.success) {
									alert.error(response.message);
									$scope.loadingRestores = false;
									return false;
								}

								for(var i = 0; i < response.data.queue.length; i++)
								{
									var data = response.data.queue[i];

									var filename = '';
									if(data.status > 100) filename = lang.t("Download Failed");
									else filename = lang.t("Download in Progress");

									$scope.downloads.push({
										queue_id: data._id,
										status: data.status,
										ready: !(parseInt(data.status) > 100 || parseInt(data.status) < 100),
										filename: filename,
										download_id: data.download_id
									});
								}

								$scope.loadingDownloads = false;
								return true;
							});

							return true;
						});
					};
					*/

					/*
					$scope.getRestores = function () {

						$scope.loadingRestores = true;

						api.listQueueItems({ type: consts.QUEUE_ITEM_TYPE_RESTORE, snap_item_id: $scope.typeId }, function(response) {

							$scope.restores = [];

							if(!response.success) {
								alert.error(response.message);
								$scope.loadingRestores = false;
								return false;
							}

							for(var i = 0; i < response.data.queue.length; i++)
							{
								var data = response.data.queue[i];

								var text = '';
								if(data.status === 100) text = lang.t("Restore Completed");
								else if(data.status > 100) text = lang.t("Restore Failed");
								else text = lang.t("Restore in Progress");

								$scope.restores.push({
									_id: data._id,
									ready: data.status >= 100,
									status: data.status,
									created: data.created,
									text: text
								});
							}

							$scope.loadingRestores = false;
							return true;
						});
					};
					*/

					$scope.inQueues = function(_id) {
						for(var i = 0; i < $scope.queues.length; i++) {
							if($scope.queues[i] == _id) return i;
						}

						return null;
					};

					$scope.checkStatus = function () {

						statusInterval = $interval(function() {

							api.listQueueItems({ 
								data: { snap_item_id: $scope.typeId }, 
								success: function(data) {

									var reload = false;
									for(var i = 0; i < data.queue.length; i++) {
										var item = data.queue[i];
										var index = $scope.inQueues(item._id);
	
										if(index !== null) {
											if(item.status >= 100) {
												$scope.queues.splice(index, 1);
												reload = true;
											}
										} else if(item.status < 100) {
											$scope.queues.push(item._id);
										}
									}
	
									/*
									if(reload) {
										$scope.getDownloads();
										$scope.getRestores();
									}
									*/
								},
								failed: function (message) {
									alert.error(message);
								}
							});

						}, 3000);
					};

					$scope.getDestination = function() {

						api.getDestination({ 
							data: { _id: $scope.typeId }, 
							success: function(data) {
								$scope.typeDetails = data;
							},
							failed: function (message) {
								alert.error(message);
								$location.path('/destinations');
							}
						});
					};

					$scope.getBackup = function() {

						api.getBackupItem({ 
							data: { _id: $scope.typeId }, 
							success: function(data) {
								$scope.typeDetails = data;
								//$scope.isDirectories = consts.BACKUP_TYPE_DIRECTORY == $scope.typeDetails.type;
							},
							failed: function (message) {
								alert.error(message);
							}

						});
					};

					$scope.$on('$destroy', function() {
						if(angular.isDefined(statusInterval)) $interval.cancel(statusInterval);
					});

					$scope.init = function () {

						//$scope.checkStatus();

						switch($scope.type) {
							default:
								$location.path('/');
							break;
							case 'backup':
								if(!permissions.canManageFileBackups) $location.path('/');
								$scope.getBackup();
								//$scope.getRestores();
							break;
							case 'destination':
								if(!permissions.canManageDestinations) $location.path('/');
								$scope.isDirectories = true;
								$scope.getDestination();
							break;
						}

						//$scope.getDownloads();
						$scope.fetch({path: '/'});
						$scope.calculateCheckedAll();
					};

					$timeout($scope.init());
				}]
		);

	}
);


define('controllers/fileManagerPopup',['app'], function(app) {

		app.controller("fileManagerPopup",
			["$uibModalInstance", "$rootScope", "$scope", "$routeParams", "$interval", "$timeout", "api", "meta", "lang", "pathManager", "files", "backup",
				function($uibModalInstance, $rootScope, $scope, $routeParams, $interval, $timeout, api, meta, lang, pathManager, files, backup) {

					$routeParams.type = 'backup';
					$routeParams.id = backup._id;
					$scope.files = files;

					$scope.listPathes = [];
					for(var path in files) $scope.listPathes.push(path);

					$rootScope.$on('filesChanged', function (event, files) {
						$scope.files = {};
						for(var path in files) {
							if($scope.files[path] !== undefined) continue;
							$scope.files[path] = files[path].empty !== undefined && files[path].empty ? "Unknown" : files[path].type;
						}
					});

					$scope.ok = function () { $uibModalInstance.close($scope.files); };
					$scope.cancel = function () { $uibModalInstance.dismiss(lang.t('cancel')); };

				}]);

	}
);


define('controllers/fileBrowse',['app'], function(app) {

		app.controller("fileBrowse",
			["$uibModalInstance", "$scope", "$interval", "$timeout", "api", "meta", "lang", "alert", "util", "pathManager", "listPaths",
				function($uibModalInstance, $scope, $interval, $timeout, api, meta, lang, alert, util, pathManager, listPaths) {

					$scope.manager = pathManager.new(listPaths);

					$scope.files = [];
					$scope.selectedTree = {};
					$scope.loadingFiles = false;
					$scope.breadcrumbs = [];
					$scope.filesIndex = {};
					$scope.filesPageIndex = {};
					$scope.currentFile = {path: '/'};

					$scope.toggleFile = function(file) {
						if($scope.manager.isExists(file.path)) $scope.manager.removePath(file.path);
						else $scope.manager.addPath(file.path);
					};

					$scope.noParentDirectory = function() {
						return $scope.breadcrumbs.length <= 1;
					};

					$scope.goParentDirectory = function() {
						if($scope.noParentDirectory()) return;
						$scope.fetch($scope.breadcrumbs[$scope.breadcrumbs.length-2], false, true);
					};

					$scope.isDisabled = function(file) {
						return $scope.manager.isChildren(file.path);
					};

					$scope.isChecked = function(file) {
						return $scope.manager.isExists(file.path) || $scope.manager.isChildren(file.path);
					};

					$scope.isChildrenChecked = function(file) {
						return $scope.manager.isParent(file.path);
					};

					var calculateBreadcrumbs = function(file) {
						var path = file.path;
						if(path.substr(-1) === '/') path = path.substr(0, path.length-1);
						if(path.substr(0, 1) === '/') path = path.substr(1);

						var parts = path ? path.split('/') : [];

						$scope.breadcrumbs = [{name:"", path:"/"}];

						var fullpath = '';
						for(var i = 0; i < parts.length; i++) {
							fullpath += '/' + parts[i];
							$scope.breadcrumbs.push({name: parts[i], path: fullpath});
						}
					};

					var handleResponse = function(data, file) {
						$scope.filesIndex[file.path] = data;
						$scope.filesPageIndex[file.path] = metaFiles.getCurrentPage();
						$scope.files = data.files;

						for(var i = 0; i < $scope.files.length; i++) {
							$scope.files[i].checked = $scope.manager.isExists($scope.files[i].path);
						}

						/*
						$scope.files.sort(function(a, b){
							if(a.type == 'Directory' && b.type != 'Directory') return -1;
							if(b.type == 'Directory' && a.type != 'Directory') return 1;
							return a.name < b.name ? -1 : 1;
						});
						
						 */

						$scope.loadingFiles = false;
					};

					var metaFiles = meta.new("file_browse");
					$scope.meta = metaFiles;
					$scope.metaData = metaFiles.getData();

					if(!metaFiles.getSortBy()) metaFiles.setSortBy("type");
					if(!metaFiles.getSortDirection()) metaFiles.setSortDirection("asc");
					metaFiles.setSortFields(["name","type","size","created"]);
					metaFiles.setPageSize(25);
					metaFiles.setPageSizes([5,10,25,50]);
					metaFiles.setTotalItems($scope.files.length);

					$scope.fetch = function(file, resetPagination, restorePagination) {
						if(file === undefined || file.path === undefined) file = $scope.currentFile;
						
						$scope.currentFile = file;
						$scope.loadingFiles = true;
						$scope.files = [];

						calculateBreadcrumbs(file);

						/*
						if($scope.filesIndex[file.path] !== undefined)
						{
							handleResponse($scope.filesIndex[file.path], file);
							return;
						}
						
						 */

						if(resetPagination) {
							metaFiles.setCurrentPage(1);
						} else if(restorePagination) {
							var page = $scope.filesPageIndex[file.path] === undefined ? 1 : $scope.filesPageIndex[file.path];
							metaFiles.setCurrentPage(page);
						}

						var apiParams = {
							sort: {},
							skip: metaFiles.getSkip(),
							limit: metaFiles.getPageSize(),
							find: {},
							filter: ''
						};

						apiParams._id = $scope.typeId;
						apiParams.type = $scope.type;
						apiParams.path = file.path;
						apiParams.sort[metaFiles.getSortBy()] = metaFiles.getSortDirectionInt();
						
						api.fileBrowse({ 
							data: apiParams, 
							
							success: function(data) {
								for(var i = 0; i < data.files.length; i++) {
									data.files[i].path = file.path + (file.path === '/' ? '' : '/') + data.files[i].name;
								}
	
								handleResponse(data, file);

								metaFiles.setTotalItems(data.total);
								metaFiles.calculate(data.files);

							},
							failed: function (message) {
								alert.error(message);
							}
						});

					};

					$timeout($scope.fetch({path: '/'}));

					$scope.ok = function () { $uibModalInstance.close($scope.manager.getSelected()); };
					$scope.cancel = function () { $uibModalInstance.dismiss(lang.t('cancel')); };

				}]
		);

	}
);


define('controllers/downloads',['app'], function(app) {
	
	app.controller("downloads",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "alert",
			function ($rootScope, $scope, $location, $timeout, api, meta, alert) {

				$rootScope.$emit('menuItem', 'Downloads');
				$scope.loading = false;
				$scope.downloads = [];

				meta = meta.new("downloads");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["created", "size"]);
				meta.setTotalItems($scope.downloads.length);

				$scope.directDownload = function(download) {
					window.location = window.PAGE.path.download + "&download_id=" + download._id;
				};

				$scope.saveNotes = function (download, keyEvent) {
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageDownloadNotes({ 
						data: { _id: download._id, notes: download.notes },
						success: function (data, message) {
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
					download.editing = false;
				};

				$scope.fetch = function () {

					if($scope.loading) return;
					$scope.loading = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.downloads = [];

					api.listDownloads({ 
						data: apiParams, 
						success: function(data) {
							$scope.loading = false;
							meta.setTotalItems(data.total);
							meta.calculate(data.downloads);
							$scope.downloads = data.downloads;
						}
					});

				};

				$timeout($scope.fetch());
			}
		]
	);
});


define('controllers/accountSelection',['app'], function(app) {

	app.controller('accountSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "lang", "account",
			function($uibModalInstance, $scope, $timeout, api, lang, account) {

				$scope.loading = false;
				$scope.accounts = [];
				$scope.selectedAccount = {};

				$scope.selectAccount = function(account) {
					$scope.selectedAccount = account;
				};
				
				$scope.fetch = function () {

					$scope.loading = true;

					api.listAccounts({ 
						data: { login_only: 0, sort: { username: 1 }, limit: 9999999 },
						success: function (data) {
							for (var i = 0; i < data.accounts.length; i++) {
								if(account === data.accounts[i].username) $scope.selectedAccount = data.accounts[i];
								$scope.accounts.push(data.accounts[i]);
							}
	
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetch());

				$scope.ok = function () {
					$uibModalInstance.close($scope.selectedAccount);
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/restore',['app'], function(app) {
	app.controller("restore",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "permissions", "confirm", "alert", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, permissions, confirm, alert, consts, lang, popup) {
				$rootScope.$emit('menuItem', 'Restore');

				$scope.changed = false;
				$scope.restoreSectionChanged = false;
				$scope.hideTabs = !permissions.canManageAccounts && !permissions.canManageDirectoryBackups;

				$scope.restoreSections = [
					{ _id: 'singleaccount', 	name: lang.t('Single Account'), 	template: 'restoreSingleAccount', 		icon: 'fa-user', 	hidden: false },
					{ _id: 'multiaccount', 		name: lang.t('Multi Account'), 		template: 'restoreMultiAccount', 		icon: 'fa-users', 	hidden: !permissions.canManageAccounts },
					{ _id: 'directories', 		name: lang.t('Directories'), 	 	template: 'restoreDirectories',			icon: 'fa-folder', 	hidden: !permissions.canManageDirectoryBackups },
					{ _id: 'disasterrecovery', 	name: lang.t('ISO Images'), 	 	template: 'restoreDisasterRecovery',	icon: 'fa-compact-disc', 	hidden: !permissions.canManageDisasterRecoveryBackups }
				];

				$scope.getRestoreSection = function (section_id) {
					for(var i = 0; i < $scope.restoreSections.length; i++) {
						if($scope.restoreSections[i]._id === section_id) {
							return $scope.restoreSections[i];
						}
					}

					return $scope.restoreSections[0];
				};

				$scope.changeRestoreSection = function (section) {

					if(!$scope.changed) {
						$location.path('/restore/' + section._id);
						return;
					}

					$scope.restoreSectionChanged = true;
				};

				$scope.loadRestoreSection = function (section) {
					$scope.currentRestoreSection = section;
					$scope.restoreSection = $scope.includePath(section.template);
				};

				$scope.loadRestoreSection($scope.getRestoreSection($routeParams.section ? $routeParams.section : 'singleaccount'));

			}
		]
	);
});


define('controllers/restoreMultiAccount',['app'], function(app) {
	app.controller("restoreMultiAccount",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "permissions", "confirm", "alert", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, permissions, confirm, alert, consts, lang, popup) {

				$scope.today = new Date();
				$scope.loadingAccounts = false;
				$scope.destinations = [{label:lang.t("Any Destination"),value:''}];
				$scope.action = 'restore';
				$scope.accounts = [];
				$scope.account_details = {};
				$scope.owner_details = {};
				$scope.excluded = [];
				$scope.restore_conditions = [];
				$scope.conditions = {};
				$scope.exclude_type = 0;
				$scope.exclude_loading = false;
				$scope.encryption_keys = {};
				$scope.total_accounts = 0;
				$scope.backup_contains = consts.BACKUP_TYPE_ACCOUNT_FULL;
				$scope.options = {};
				$scope.tags = {};
				$scope.autocomplete = { accountText: '', ownerText: '', tagText: '' };
				$scope.filters = {
					accounts: [],
					show_oldest: 0,
					date_start: '',
					date_end: '',
					account_status: 0,
					account_suspended: 0,
					locked: 0,
					encrypted: 0,
					backup_structure: 0,
					backup_contains: 0,
					destination: '',
					owned_by: [],
					tags: [],
					use_damaged: 0
				};

				$scope.$watch('action', function () {
					$scope.options = {allbackups:0};
					if($scope.action == 'unlock') $scope.filters.locked = 1;
					else if($scope.action == 'lock') $scope.filters.locked = 2;
					else $scope.filters.locked = 0;
				});

				$scope.account_types_disabled = {};
				$scope.account_types_disabled[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = true;

				$scope.account_types = [
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG], value: consts.BACKUP_TYPE_ACCOUNT_CONFIG },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR], value: consts.BACKUP_TYPE_ACCOUNT_HOMEDIR },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES], value: consts.BACKUP_TYPE_ACCOUNT_DATABASES },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS], value: consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS], value: consts.BACKUP_TYPE_ACCOUNT_EMAILS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FTP], value: consts.BACKUP_TYPE_ACCOUNT_FTP },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS], value: consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS], value: consts.BACKUP_TYPE_ACCOUNT_DOMAINS },
					{ label: consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES], value: consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES }
				];

				var metaAcct = meta.new("restore_and_download");
				$scope.meta = metaAcct;
				$scope.metaData = metaAcct.getData();

				metaAcct.setSortReverse(false);
				if(!metaAcct.getSortBy()) metaAcct.setSortBy("username");
				if(!metaAcct.getSortDirection()) metaAcct.setSortDirection("asc");
				metaAcct.setSortFields(["username", "owner"]);
				metaAcct.setTotalItems($scope.accounts.length);

				$scope.containsChecked = function(type, contains) {
					if(contains === undefined) contains = $scope;
					return ( type & contains.backup_contains );
				};

				$scope.toggleContains = function(type, contains) {
					if(contains === undefined) contains = $scope;
					if($scope.containsChecked(type, contains)) contains.backup_contains ^= type;
					else contains.backup_contains |= type;
				};

				$scope.isExcluded = function(account) {
					return $scope.excluded.indexOf(account.username) >= 0;
				};

				$scope.toggleExclude = function(account) {

					if(!$scope.isExcluded(account)) $scope.excluded.push(account.username);
					else {
						var index = $scope.excluded.indexOf(account.username);
						$scope.excluded.splice(index, 1);
					}
				};

				$scope.toggleExcludeAll = function() {

					if($scope.exclude_loading) return;
					$scope.exclude_loading = true;

					if($scope.exclude_type === 0) {
						$scope.exclude_type = 1;

						api.listAccountsByFilters({ 
							data: { filters: $scope.filters, limit: 9999999 }, 
							success: function(data) {
								$scope.excluded = [];
								for(var i = 0; i < data.accounts.length; i++) {
									var account = data.accounts[i].account;
									$scope.excluded.push(account.username);
								}
	
								$scope.exclude_loading = false;
							}
						});

					} else {
						$scope.exclude_loading = false;
						$scope.exclude_type = 0;
						$scope.excluded = [];
					}
				};

				$scope.gotItems = function(types) {
					var check = 0;
					for(var i = 0; i < types.length; i++) check |= types[i];
					return $scope.backup_contains & check;
				};

				$scope.fetchNoResetExcludes = function (callback) {
					$scope.fetch(callback, true);
				};
				
				$scope.fetch = function(callback, dontReset) {
					if($scope.loadingAccounts) return;

					if(callback === undefined || typeof callback !== 'function') callback = function(){};
					$scope.loadingAccounts = true;
					$scope.exclude_type = 0;
					if(dontReset === undefined || !dontReset) $scope.excluded = [];

					var apiParams = {
						skip: metaAcct.getSkip(),
						limit: metaAcct.getPageSize(),
						filters: $scope.filters
					};

					if(window.PAGE.info.utcOffset){
						if(apiParams.filters.date_start) apiParams.filters.date_start.utcOffset(window.PAGE.info.utcOffset, true);
						if(apiParams.filters.date_end) apiParams.filters.date_end.utcOffset(window.PAGE.info.utcOffset, true);
					}

					$scope.accounts = [];

					api.listAccountsByFilters({ 
						data: apiParams, 
						success: function(data) {
							metaAcct.setTotalItems(data.total);
							metaAcct.calculate(data.accounts);
							$scope.accounts = data.accounts;
							$scope.total_accounts = data.total;
							$scope.loadingAccounts = false;
							callback();
						}
					});
				};

				$scope.tagsSelection = function () {

					popup.open({
						template: 'tagsSelection',
						scope: $scope,
						resolve: {
							tags: function() { return $scope.filters.tags; },
							type: function () { return consts.TAG_TYPE_ACCOUNT; }
						}
					}).result.then(function(selected) {
						$scope.filters.tags = selected;
					}, function () {});
				};

				$scope.ownersSelection = function () {
					popup.open({
						template: 'accountsSelection',
						scope: $scope,
						resolve: {
							accounts: function() { return $scope.filters.owned_by; },
							includeOrphan: function () { return 0; },
							callParams: function () { return ''; }
						}
					}).result.then(function(selected) {
						$scope.filters.owned_by = selected;
					}, function () {});
				};

				$scope.accountsSelection = function () {
					popup.open({
						template: 'accountsSelection',
						scope: $scope,
						resolve: {
							accounts: function() { return $scope.filters.accounts; },
							includeOrphan: function () { return 1; },
							callParams: function () { return ''; }
						}
					}).result.then(function(selected) {
						$scope.filters.accounts = selected;
					}, function () {});
				};

				$scope.searchTags = function(query) {

					if(!query) return [];

					var deferred = $q.defer();

					api.listTags({ 
						data: { filter: query, sort: { name: 1 }, find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function(data) {
							var results = [];
							for(var i = 0; i < data.tags.length; i++) {
								var tag = data.tags[i];
								if($scope.filters.tags.indexOf(tag._id) >= 0) continue;
								results.push(tag);
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.searchOwners = function(query) {
					if(query) {

						var deferred = $q.defer();
						api.listAccounts({ 
							data: { filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) {
	
									var account = data.accounts[i];
	
									if($scope.filters.owned_by.indexOf(account.username) >= 0) continue;
									results.push(account);
								}
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.searchAccounts = function(query) {
					if(query) {

						var deferred = $q.defer();
						api.listAccounts({ 
							data: { include_orphan: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) {
									var account = data.accounts[i];
									if($scope.filters.accounts.indexOf(account.username) >= 0) continue;
									results.push(account);
								}
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.selectTag = function(tag) {
					if(tag === undefined) return;
					$scope.filters.tags.push(tag._id);
					$scope.autocomplete.tagText = '';
				};

				$scope.selectOwner = function(account) {
					if(account === undefined) return;
					$scope.filters.owned_by.push(account.username);
					$scope.owner_details[account.username] = account;
					$scope.autocomplete.ownerText = '';
				};

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					$scope.filters.accounts.push(account.username);
					$scope.account_details[account.username] = account;
					$scope.autocomplete.accountText = '';
				};

				$scope.isContainsDisabled = function(type) {
					return $scope.account_types_disabled[type] !== undefined && $scope.account_types_disabled[type];
				};

				$scope.manageBackupLock = function() {

					var totalAccounts = $scope.total_accounts-$scope.excluded.length;

					if(totalAccounts <= 0) {
						alert.error(lang.t("Your filters didn't result with any account"));
						return;
					}

					var locked = $scope.action == 'lock' ? 1 : 0;

					confirm.open({
						message: lang.t("Total of %s accounts backups will be " + (locked ? "locked" : "unlocked"), totalAccounts),
						confirm: function () {
							api.manageMultiBackupLock({ 
								data: { locked: locked, filters: $scope.filters, options: $scope.options, excluded: $scope.excluded }, 
								success: function (data, message) {
									alert.success(message);
									$scope.fetch();
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.addToQueue = function() {

					var totalAccounts = $scope.total_accounts-$scope.excluded.length;

					if(totalAccounts <= 0) {
						alert.error(lang.t("Your filters didn't result with any account"));
						return;
					}

					var confirmMessage = '';
					var type = '';

					switch($scope.action) {
						case 'restore':
							type = consts.QUEUE_ITEM_TYPE_RESTORE;
							confirmMessage = lang.t("Total of %s accounts will be restored", totalAccounts);
							for(var i = 0; i < $scope.restore_conditions.length; i++) {
								var condition = $scope.restore_conditions[i];
								if($scope.conditions[condition._id] === undefined || !$scope.conditions[condition._id]) {
									alert.error(lang.t("Please accept all restore conditions"));
									return;
								}
							}
						break;

						case 'download':
							type = consts.QUEUE_ITEM_TYPE_DOWNLOAD;
							confirmMessage = lang.t("Total of %s accounts backups will be downloaded", totalAccounts);
						break;
					}

					confirm.open({
						message: confirmMessage,
						confirm: function () {
							api.addMultiAccountQueueItems({
								data: {
									type: type,
									filters: $scope.filters,
									options: $scope.options,
									backup_contains: $scope.backup_contains,
									encryption_keys: $scope.encryption_keys,
									excluded: $scope.excluded
								}, 
								success: function (data, message) {
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});
				};

				$scope.setActionMessage = function() {

					var message = '';
					var total = $scope.total_accounts-$scope.excluded.length;
					
					switch($scope.action) {
						case 'restore': message = lang.t("Total of %s filtered accounts will be restored", total); break;
						case 'download': message = lang.t("Total of %s backups will be downloaded (one backup for each filtered account)", total); break;
						case 'lock':
							if($scope.options.allbackups) message = lang.t("All backups related to %s filtered accounts will be locked", total);
							else message = lang.t("Total of %s backups will be locked (one backup for each filtered account)", total);
							break;
						case 'unlock':
							if($scope.options.allbackups) message = lang.t("All backups related to %s filtered accounts will be unlocked", total);
							else message = lang.t("Total of %s backups will be unlocked (one backup for each filtered account)", total);
							break;
					}

					if(!message) return;

					$scope.actionMessage = {
						message: message,
						type: "warning"
					};
				};

				$scope.filteredMessage = function() {
					$scope.filteredAccountsStatus = {
						message: lang.t("Total of %s accounts will be affected using selected filters", $scope.total_accounts-$scope.excluded.length),
						type: "info"
					};
				};

				$scope.deleteSnapshot = function(backup) {

					confirm.open({
						message: lang.t("Are you sure you want to delete this snapshot?"),
						confirm: function () {

							api.deleteSnapshot({
								data: {
									_id: backup._id
								},
								success: function (data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {
						}
					});
				};

				$scope.$watch('excluded', function () {
					$scope.filteredMessage();
					$scope.setActionMessage();
				}, true);

				$scope.$watch('total_accounts', function () {
					$scope.filteredMessage();
					$scope.setActionMessage();
				}, true);

				$scope.$watch('options', function () {
					$scope.filteredMessage();
					$scope.setActionMessage();
				}, true);

				$scope.$watch('filters', function () {
					if($scope.filters.account_status != 1) {
						if(!$scope.containsChecked(consts.BACKUP_TYPE_ACCOUNT_CONFIG, $scope.filters)) $scope.toggleContains(consts.BACKUP_TYPE_ACCOUNT_CONFIG, $scope.filters);
						if(!$scope.containsChecked(consts.BACKUP_TYPE_ACCOUNT_CONFIG)) $scope.toggleContains(consts.BACKUP_TYPE_ACCOUNT_CONFIG);
						$scope.account_types_disabled[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = true;
					} else {
						$scope.account_types_disabled[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = false;
					}

					$scope.fetch(function () {
						$scope.filteredMessage();
						$scope.setActionMessage();
					});

				}, true);

				if(permissions.canManageDestinations) {
					api.listDestinations({ 
						success: function (data) {
							for(var i = 0; i < data.destinations.length; i++) {
								var destination = data.destinations[i];
								$scope.destinations.push({label: destination.name,value:destination._id});
							}
						}
					});
				}

				api.listTags({ 
					data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
					success: function (data) {
						for(var i = 0; i < data.tags.length; i++) $scope.tags[data.tags[i]._id] = data.tags[i];
					}
				});

				api.listRestoreConditions({
					data: { find: { disabled: false } },
					success: function (data) {
						$scope.restore_conditions = data.conditions;
					}
				});

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/restoreSingleAccount',['app'], function(app) {
	app.controller("restoreSingleAccount",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "permissions", "confirm", "alert", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, permissions, confirm, alert, consts, lang, popup) {


				if(!permissions.canManageAccounts) {
					$scope.$emit("accountChanged", $rootScope.loggedAccount);
				}
				
				$scope.autocomplete = {accountText:''};

				$scope.selectAccount = function(account) {
					if(account === undefined) return;
					//$scope.selectedAccount = account.username;
					//$scope.autocomplete.accountText = account.username;

					$scope.$emit("accountChanged", account);
				};

				$scope.clearAccount = function () {
					$scope.autocomplete = {accountText:''};
					$scope.$emit("accountChanged", {});
				}
				
				$scope.searchAccounts = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({
							data: { login_only: 1, filter: query, sort: { username: 1 } },
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};
			}
		]
	);
});


define('controllers/restoreDirectories',['app'], function(app) {
	app.controller("restoreDirectories",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "permissions", "confirm", "alert", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, permissions, confirm, alert, consts, lang, popup) {

				$scope.isAllChecked = false;

				$scope.backups = [];
				$scope.backups_selected = [];
				$scope.files = {};
				$scope.filter = '';

				var changeBackupSelected = function (backup) {

					var position = -1;
					for (var i = 0; i < $scope.backups_selected.length; i++) {
						if(backup.backup._id === $scope.backups_selected[i].backup._id) {
							position = i;
							break;
						}
					}

					if(backup.checked) {
						if(position >= 0) return;
						$scope.backups_selected.push(backup);
					} else {
						if(position < 0) return;
						$scope.backups_selected.splice(position, 1);
					}
				};

				$scope.fileBrowse = function(backup) {
					popup.open({
						size: "xl",
						template: 'fileManagerPopup',
						scope: $scope,
						resolve: {
							files: function() { return $scope.files[backup.backup._id] !== undefined ? $scope.files[backup.backup._id] : {}; },
							backup: function() { return backup.backup; }
						}
					}).result.then(function(files) {
						$scope.files[backup.backup._id] = files;
					}, function(){});
				};

				$scope.totalFiles = function(backup) {
					if($scope.files[backup.backup._id] === undefined) return null;
					var output = 0;
					for(var path in $scope.files[backup.backup._id]) output++;

					if(!output) {
						delete $scope.files[backup.backup._id];
						return null;
					}

					return output;
				};

				$scope.changeBackup = function(backup) {

					backup.options = [];

					if(backup.new_id === backup.backup._id) {
						backup.options_real = {};
						backup.new_id = '';
						return;
					}

					delete $scope.files[backup.backup._id];

					var newBackup = backup.options_real[backup.new_id];
					for(var key in newBackup) backup.backup[key] = newBackup[key];

					//$scope.selected_full = '';
					//$scope.selected_full_items = [];
					backup.options_real = {};
					backup.new_id = '';
				};

				$scope.selectBackup = function(backup) {

					backup.new_id = backup.backup._id;
					backup.options = [];
					backup.options_real = {};

					var apiParams = {
						type: backup.backup.backup_type,
						contains: backup.backup.backup_contains,
						name: backup.backup.name,
						sort: { created: -1 }
					};

					api.listBackupForTypeName({
						data: apiParams,
						success: function (data) {
							for(var i = 0; i < data.backups.length; i++) {
								backup.options.push({ _id: data.backups[i]._id, display: lang.d(data.backups[i].created, 'shorttime') });
								backup.options_real[data.backups[i]._id] = data.backups[i];
							}
						}
					});
				};

				$scope.checkAll = function () {
					//$scope.isAllChecked = !$scope.isAllChecked;
					for (var i = 0; i < $scope.backups.length; i++) {
						var backup = $scope.backups[i];
						backup.checked = $scope.isAllChecked;
						changeBackupSelected(backup);
					}
				};
				
				$scope.unCheckAll = function () {
					$scope.isAllChecked = false;
					for (var i = 0; i < $scope.backups.length; i++) {
						var backup = $scope.backups[i];
						backup.checked = false;
						changeBackupSelected(backup);
					}
					$scope.files = {};
				};
				
				$scope.checkChanged = function (backup) {

					if(backup !== undefined) changeBackupSelected(backup);
					
					var state = ($scope.backups.length > 0);
					for (var i = 0; i < $scope.backups.length; i++) {
						var cbackup = $scope.backups[i];
						if(!cbackup.checked) {
							$scope.isAllChecked = false;
							delete $scope.files[cbackup.backup._id];
							state = false;
						}
					}

					$scope.isAllChecked = state;
				};
				
				$scope.saveNotes = function (backup, keyEvent) {
					backup.backup.notes = backup.backup.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageBackupNotes({
						data: { _id: backup.backup._id, notes: backup.backup.notes },
						success: function (data, message) { alert.success(message); },
						failed: function (message) { alert.error(message); },
					});
					backup.editing = false;
				};

				$scope.getChecked = function () {
					var ids = [];
					for(var i = 0; i < $scope.backups_selected.length; i++) ids.push($scope.backups_selected[i].backup._id);
					return ids;
				};

				$scope.getCheckedParents = function () {
					var ids = [];
					for(var i = 0; i < $scope.backups_selected.length; i++) ids.push($scope.backups_selected[i].backup.parent_id);
					return ids;
				};

				$scope.restore = function() {
					var ids = $scope.getChecked();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}

					confirm.open({
						title: lang.t("RESTORE NOTICE"),
						message: 
							lang.t("To guarantee the safety and integrity of your system, the Files and/or Directories selected will be restored with a temporary file/directory name at its original location.") + "<br />" +
							lang.t("For example, when restoring %s folder, JetBackup will restore it at %s", "<strong>/etc</strong>", "<strong>/etc.jetbackup.xxxx</strong>") + "<br /><br />" +
							"<strong>" + lang.t("YOU ARE RESPONSIBLE") + "</strong> " + lang.t("for completing the restoration process manually.") + "<br /><br />" +
							lang.t("Please take necessary precautions before restoring core system files and/or directories to avoid any unintended issues with your server.") + "<br /><br />" +
							lang.t("For more information, please visit") + " <a style='color: #fd6b2b;' href='https://docs.jetbackup.com/v5.2/adminpanel/restoreAndDownload.html#directories' target='_blank'>" + lang.t("Directory Restore Documentation") + "</a>.",
						//cancelLabel: lang.t("No, let me set schedules"),
						confirmLabel: lang.t("Restore Selected Items"),
						confirm: function () {
							api.addQueueItems({
								data: { type: consts.QUEUE_ITEM_TYPE_RESTORE, items: ids, files: $scope.files },
								success: function (data, message) {
									alert.success(message);
									$scope.unCheckAll();
									$scope.files = {};
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						}
					});

				};

				$scope.download = function() {

					var ids = $scope.getChecked();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}
					
					api.addQueueItems({
						data: { type: consts.QUEUE_ITEM_TYPE_DOWNLOAD, items: ids, files: $scope.files },
						success: function (data, message) {
							alert.success(message);
							$scope.unCheckAll();
							$scope.files = {};
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.lock = function() {

					var ids = $scope.getCheckedParents();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}
					popup.open({
						size: "lg",
						template: 'backupLockSelection',
						scope: $scope,
					}).result.then(function(ttl) {

						api.manageBackupLock({
							data: { _id: ids, lock_ttl: ttl, locked: 1 },
							success: function(data, message) {

								var parents = [];
								for(var i = 0; i < $scope.backups.length; i++) {
									if(!$scope.backups[i].checked) continue;
									if(!parents.includes($scope.backups[i].backup.parent_id)) parents.push($scope.backups[i].backup.parent_id);
								}

								
								if(ttl) {
									var ttlDate = new Date();
									ttlDate.setDate(ttlDate.getDate() + ttl);
								}
								
								for(var i = 0; i < $scope.backups.length; i++) {
									if(!parents.includes($scope.backups[i].backup.parent_id)) continue;
									$scope.backups[i].backup.lock = true;
									$scope.backups[i].backup.lock_ttl = ttl ? moment(ttlDate) : 0;
								}

								alert.success(message);
							},
							failed: function (message) {
								alert.error(message);
							}
						});

					});

				};

				$scope.unlock = function() {

					var ids = $scope.getCheckedParents();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}

					api.manageBackupLock({
						data: { _id: ids, locked: 0 },
						success: function(data, message) {

							var parents = [];
							for(var i = 0; i < $scope.backups.length; i++) {
								if(!$scope.backups[i].checked) continue;
								if(!parents.includes($scope.backups[i].backup.parent_id)) parents.push($scope.backups[i].backup.parent_id);
							}

							for(var i = 0; i < $scope.backups.length; i++) {
								if(!parents.includes($scope.backups[i].backup.parent_id)) continue;
								$scope.backups[i].backup.lock = false;
								$scope.backups[i].backup.lock_ttl = 0;
							}

							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};
				
				var getBackupData = function (backup) {
					for(var j = 0; j < $scope.backups_selected.length; j++) if(backup.backup._id === $scope.backups_selected[j].backup._id)  return $scope.backups_selected[j];
					return backup;
				};

				$scope.deleteSnapshot = function(backup) {

					confirm.open({
						message: lang.t("Are you sure you want to delete this snapshot? Please note that this will affect all other snapshot items related to this snapshot item"),
						confirm: function () {

							api.deleteSnapshot({
								data: {
									_id: backup.parent_id
								},
								success: function (data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {
						}
					});
				};

				$scope.fetch = function () {

					api.listBackupForDirectories({
						data: {
							filter: $scope.filter
						},
						success: function (data) {
							var backups = [];
							for(var i = 0; i < data.directories.length; i++) {
								var backup = data.directories[i];
								backups.push(getBackupData(backup));
							}
							$scope.backups = backups;
							$scope.checkChanged();
						},
						fail: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.fetch();
			}
		]
	);
});


define('controllers/restoreDisasterRecovery',['app'], function(app) {
	app.controller("restoreDisasterRecovery",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "meta", "permissions", "confirm", "alert", "consts", "lang", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, meta, permissions, confirm, alert, consts, lang, popup) {

				$scope.isAllChecked = false;

				$scope.backups = [];
				$scope.backups_selected = [];
				$scope.files = {};
				$scope.filter = '';
				$scope.lock_options = { ttl: 0 }

				var changeBackupSelected = function (backup) {

					var position = -1;
					for (var i = 0; i < $scope.backups_selected.length; i++) {
						if(backup._id === $scope.backups_selected[i]._id) {
							position = i;
							break;
						}
					}

					if(backup.checked) {
						if(position >= 0) return;
						$scope.backups_selected.push(backup);
					} else {
						if(position < 0) return;
						$scope.backups_selected.splice(position, 1);
					}
				};

				$scope.checkAll = function () {
					//$scope.isAllChecked = !$scope.isAllChecked;
					for (var i = 0; i < $scope.backups.length; i++) {
						var backup = $scope.backups[i];
						backup.checked = $scope.isAllChecked;
						changeBackupSelected(backup);
					}
				};
				
				$scope.unCheckAll = function () {
					$scope.isAllChecked = false;
					for (var i = 0; i < $scope.backups.length; i++) {
						var backup = $scope.backups[i];
						backup.checked = false;
						changeBackupSelected(backup);
					}
					$scope.files = {};
				};
				
				$scope.checkChanged = function (backup) {

					if(backup !== undefined) changeBackupSelected(backup);
					
					var state = ($scope.backups.length > 0);
					for (var i = 0; i < $scope.backups.length; i++) {
						var cbackup = $scope.backups[i];
						if(!cbackup.checked) {
							$scope.isAllChecked = false;
							delete $scope.files[cbackup._id];
							state = false;
						}
					}

					$scope.isAllChecked = state;
				};
				
				$scope.saveNotes = function (backup, keyEvent) {
					backup.notes = backup.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageBackupNotes({
						data: { _id: backup._id, notes: backup.notes },
						success: function (data, message) { alert.success(message); },
						failed: function (message) { alert.error(message); },
					});
					backup.editing = false;
				};

				$scope.getChecked = function () {
					var ids = [];
					for(var i = 0; i < $scope.backups_selected.length; i++) ids.push($scope.backups_selected[i]._id);
					return ids;
				};

				$scope.getCheckedParents = function () {
					var ids = [];
					for(var i = 0; i < $scope.backups_selected.length; i++) ids.push($scope.backups_selected[i].parent_id);
					return ids;
				};

				$scope.download = function() {

					var ids = $scope.getChecked();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}
					
					api.addQueueItems({
						data: { type: consts.QUEUE_ITEM_TYPE_DOWNLOAD, items: ids, files: $scope.files },
						success: function (data, message) {
							alert.success(message);
							$scope.unCheckAll();
							$scope.files = {};
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.lock = function() {

					var ids = $scope.getCheckedParents();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}

					api.manageBackupLock({
						data: { _id: ids, lock_ttl: $scope.lock_options.ttl, locked: 1 },
						success: function(data, message) {

							for(var i = 0; i < $scope.backups.length; i++) {
								if(!$scope.backups[i].checked) continue;
								$scope.backups[i].lock = 1;
								$scope.backups[i].lock_ttl = $scope.lock_options.ttl;
							}

							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.unlock = function() {

					var ids = $scope.getCheckedParents();
					if(ids.length <= 0 ) {
						alert.error(lang.t("You must select at least one backup"));
						return;
					}

					api.manageBackupLock({
						data: { _id: ids, locked: 0 },
						success: function(data, message) {

							for(var i = 0; i < $scope.backups.length; i++) {
								if(!$scope.backups[i].checked) continue;
								$scope.backups[i].lock = 0;
								$scope.backups[i].lock_ttl = 0;
							}

							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};
				
				var getBackupData = function (backup) {
					for(var j = 0; j < $scope.backups_selected.length; j++) if(backup._id === $scope.backups_selected[j]._id)  return $scope.backups_selected[j];
					return backup;
				};

				$scope.deleteSnapshot = function(backup) {

					confirm.open({
						message: lang.t("Are you sure you want to delete this snapshot?"),
						confirm: function () {

							api.deleteSnapshot({
								data: {
									_id: backup.parent_id
								},
								success: function (data, message) {
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {
						}
					});
				};

				$scope.fetch = function () {

					api.listBackupForDisasterRecovery({
						success: function (data) {
							var backups = [];
							for(var i = 0; i < data.images.length; i++) {
								var backup = data.images[i];
								backups.push(getBackupData(backup));
							}
							$scope.backups = backups;
							$scope.checkChanged();
						},
						fail: function (message) {
							alert.error(message);
						}
					});
					
				};

				$scope.fetch();
			}
		]
	);
});


define('controllers/accountBackups',['app'], function(app) {
	
	app.controller("accountBackups",
		["$uibModalInstance","$rootScope", "$scope", "$q", "$location", "$timeout", "$window", "api", "meta", "util", "permissions", "confirm", "consts", "lang", "alert", "popup", "account",
			function ($uibModalInstance, $rootScope, $scope, $q, $location, $timeout, $window, api, meta, util, permissions, confirm, consts, lang, alert, popup, account) {

				$rootScope.$emit('menuItem', 'Restore');

				$scope.accountData = account;
				if(!$scope.accountData) $scope.accountData = {};
				
				$scope.reset = function () {
					$scope.loading = false;
					$scope.list = {};
					$scope.list_loaded = {};
					$scope.backups = [];
					$scope.searchFilterValue = '';
					$scope.static = { isAllChecked: false };
					$scope.advanced = false;
					$scope.selected = {full:'',full_items:[]};
					$scope.summary = { enabled: false, type: '', tpl: '', gotoqueue: true };
					//$scope.summary_type = '';
					//$scope.summary_tpl = '';
					$scope.list_checked = {};
					$scope.list_checked_parents = {};
					$scope.fulls = [];
					$scope.fulls_list = {};
					$scope.conditions = {restore:{}};
					$scope.options = { owner: '', exclude: [] };
					$scope.owner = {};
					$scope.autocomplete = { accountText: '' };
					$scope.files = {};
					$scope.lock_options = { ttl: 0 };
					$scope.encryption = { encrypted: false, key: '' };
					$scope.panelConfig = {};
					$scope.require = { owner: true };
					$scope.localOptions = {chown:false};
				};
				
				$scope.reset();
				$scope.restore_conditions = [];
				$scope.currentSection = undefined;
				$scope.sections = [
					//{ _id: consts.BACKUP_TYPE_ACCOUNT_FULL, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_SHORT[consts.BACKUP_TYPE_ACCOUNT_FULL], icon: "fa-box" },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_CONFIG, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CONFIG], icon: "fa-cog", permissions: permissions.canManageConfigBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_HOMEDIR, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR], icon: "fa-folder", permissions: permissions.canManageFileBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS], icon: "fa-clock", permissions: permissions.canManageCronBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_DATABASES, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DATABASES], icon: "fa-database", permissions: permissions.canManageDatabaseBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS], icon: "fa-user-tie", permissions: permissions.canManageDatabaseBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_DOMAINS, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DOMAINS], icon: "fa-map-marker-alt", permissions: permissions.canManageDNSZoneBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES], icon: "fa-lock", permissions: permissions.canManageCertificateBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_EMAILS, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_EMAILS], icon: "fa-envelope", permissions: permissions.canManageEmailBackups },
					{ _id: consts.BACKUP_TYPE_ACCOUNT_FTP, name: consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_FTP], icon: "fa-file-alt", permissions: permissions.canManageFTPBackups }
				];

				$scope.$on("accountChanged", function(evt,data){
					$scope.accountData = data;
					$scope.reset();
					$scope.fetchFulls(function () {
						$scope.changeSection($scope.sections[0]);
					});
				});
				
				$scope.$watch('summary.type', function () {
					if(!$scope.summary.type) $scope.summary.tpl = '';
					else $scope.summary.tpl = 'accountBackups' + $scope.summary.type + 'Summary';
				});

				$scope.isTooltipEnabled = function() {
					return $window.innerWidth <= 928;
				};

				var metaAcct = meta.new("account_backups");
				$scope.meta = metaAcct;
				$scope.metaData = metaAcct.getData();

				metaAcct.setSortReverse(false);
				if(!metaAcct.getSortBy()) metaAcct.setSortBy("username");
				if(!metaAcct.getSortDirection()) metaAcct.setSortDirection("asc");
				metaAcct.setPageSizes([5,10,25,50]);
				metaAcct.setPageSize(5);
				metaAcct.setSortFields(["username", "owner"]);
				metaAcct.setTotalItems($scope.list.length);

				var replaceItem = function(item) {
					if($scope.list[item.backup_contains] === undefined) $scope.list[item.backup_contains] = [];
					for(var i = 0; i < $scope.list[item.backup_contains].length; i++) {
						if(
							$scope.list[item.backup_contains][i].name === item.name &&
							(
								item.params.engine === undefined ||
								$scope.list[item.backup_contains][i].params.engine == item.params.engine
							)
						) {
							//if($scope.list[item.backup_contains][i]._id === item._id) return;
							for(var key in item) $scope.list[item.backup_contains][i][key] = item[key];
							return;
						}
					}

					$scope.list[item.backup_contains].push(item);
				};

				var checkFull = function(contains) {
					if(!$scope.selected.full_items.length) return;
					for(var i = 0; i < $scope.selected.full_items.length; i++) {
						var item = $scope.selected.full_items[i];
						if(contains !== undefined && item.backup_contains !== contains) continue;
						item.checked = true;
						replaceItem(item);
					}
				};

				$scope.checkAll = function() {
					for(var i = 0; i < $scope.list[$scope.currentSection._id].length; i++) {
						var backup = $scope.list[$scope.currentSection._id][i];
						backup.checked = $scope.static.isAllChecked;
						if(!backup.checked && $scope.files[backup._id] !== undefined) delete $scope.files[backup._id];
					}
				};

				$scope.uncheckAll = function() {
					for(var contains in $scope.list)
						for(var i = 0; i < $scope.list[contains].length; i++) {
							var backup = $scope.list[contains][i];
							backup.checked = false;
							if($scope.files[backup._id] !== undefined) delete $scope.files[backup._id];
						}
				};

				$scope.isChecked = function() {
					for(var contains in $scope.list)
						for(var i = 0; i < $scope.list[contains].length; i++)
							if($scope.list[contains][i].checked) return true;

					return false;
				};

				$scope.getChecked = function() {
					var checked = [];
					if($scope.currentSection === undefined || $scope.list[$scope.currentSection._id] === undefined) return checked;
					for(var i = 0; i < $scope.list[$scope.currentSection._id].length; i++) if($scope.list[$scope.currentSection._id][i].checked) checked.push($scope.list[$scope.currentSection._id][i]._id);
					return checked;
				};

				$scope.getCheckedAll = function() {
					var checked = [];
					for(var contains in $scope.list)
						for(var i = 0; i < $scope.list[contains].length; i++)
							if($scope.list[contains][i].checked) checked.push($scope.list[contains][i]);
					return checked;
				};

				$scope.searchAccounts = function(query) {
					if(!query) return [];
					var deferred = $q.defer();
					api.listAccounts({ 
						data: { login_only: 1, filter: query, sort: { username: 1 } }, 
						success: function(data) {
							var results = [];
							for(var i = 0; i < data.accounts.length; i++) {
								var account = data.accounts[i];
								if(($scope.options.reseller && account.root) || (!$scope.options.reseller && account.reseller)) {
									results.push(account);
								}
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.selectNewOwner = function(account) {
					if(account === undefined) return;
					$scope.options.owner = account.username;
					$scope.owner = account;
				};
				
				$scope.resetNewOwner = function() {
					$scope.options.owner = '';
					$scope.autocomplete.accountText = '';
					$scope.owner = {};
				};
				
				$scope.changeBackup = function(backup) {

					backup.options = [];

					if(backup.new_id === backup._id) {
						backup.options_real = {};
						backup.new_id = '';
						return;
					}

					delete $scope.files[backup._id];

					var newBackup = backup.options_real[backup.new_id];
					for(var key in newBackup) backup[key] = newBackup[key];

					$scope.selected.full = '';
					$scope.selected.full_items = [];
					backup.options_real = {};
					backup.new_id = '';
				};

				$scope.selectBackup = function(backup) {

					backup.new_id = backup._id;
					backup.options = [];
					backup.options_real = {};

					var apiParams = {
						account_id: backup.account_id,
						type: backup.backup_type,
						contains: backup.backup_contains,
						name: backup.name,
						sort: { created: -1 },
						limit: 9999999
					};
					if(backup.params.engine !== undefined) apiParams.engine = backup.params.engine;
					api.listBackupForTypeName({
						data: apiParams, 
						success: function (data) {
							for(var i = 0; i < data.backups.length; i++) {
								backup.options.push({ _id: data.backups[i]._id, display: lang.d(data.backups[i].created, 'shorttime') });
								backup.options_real[data.backups[i]._id] = data.backups[i];
							}
						}
					});
				};

				$scope.checkChanged = function() {
					$scope.selected.full = '';
					$scope.selected.full_items = [];
				};

				$scope.$watch('list', function() {
					var checked = $scope.getChecked();
					$scope.static.isAllChecked = checked.length === metaAcct.getTotalItems();
				},true);

				$scope.askForEncryptionKey = function() {
					return $scope.encryption.encrypted && $scope.accountData.backup_type == 1 && $scope.accountData.encryption_key_type == 1;
				};

				$scope.lock = function() {
					var ids = [];
					for(var id in $scope.list_checked_parents) ids.push(id);

					api.manageBackupLock({ 
						data: { _id: ids, lock_ttl: $scope.lock_options.ttl, locked: 1 }, 
						success: function(data, message) {

							for(var contains in $scope.list) {
								for(var i = 0; i < $scope.list[contains].length; i++) {
									var item = $scope.list[contains][i];
									if(ids.indexOf(item.parent_id) >= 0) {
										item.lock = 1;
										item.lock_ttl = $scope.lock_options.ttl;
									}
								}
							}
	
							$uibModalInstance.close();
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.unlock = function() {
					var ids = [];
					for(var id in $scope.list_checked_parents) ids.push(id);

					api.manageBackupLock({ 
						data: { _id: ids, locked: 0 }, 
						success: function(data, message) {

							for(var contains in $scope.list) {
								for(var i = 0; i < $scope.list[contains].length; i++) {
									var item = $scope.list[contains][i];
									if(ids.indexOf(item.parent_id) >= 0) {
										item.lock = 0;
									}
								}
							}
	
							$uibModalInstance.close();
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.saveNotes = function (backup, keyEvent) {
					backup.notes = backup.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageBackupNotes({ 
						data: { _id: backup._id, notes: backup.notes },
						success: function (data, message) { alert.success(message); },
						failed: function (message) { alert.error(message); },
					});
					backup.editing = false;
				};

				$scope.fileBrowse = function(backup) {
					popup.open({
						size: "xl",
						template: 'fileManagerPopup',
						scope: $scope,
						resolve: {
							files: function() { return $scope.files[backup._id] !== undefined ? $scope.files[backup._id] : {}; },
							backup: function() { return backup; }
						}
					}).result.then(function(files) {
						$scope.files[backup._id] = files;
					}, function(){});
				};

				$scope.totalFiles = function(backup) {
					if($scope.files[backup._id] === undefined) return null;
					var output = 0;
					for(var path in $scope.files[backup._id]) output++;

					if(!output) {
						delete $scope.files[backup._id];
						return null;
					}

					return output;
				};

				$scope.fetchReal = function(callback) {
					if(callback === undefined) callback = function() {};

					if($scope.loading) return;

					if($scope.list_loaded[$scope.currentSection._id] !== undefined) {
						callback();
						return;
					}

					$scope.list_loaded[$scope.currentSection._id] = true;

					$scope.loading = true;

					$scope.list[$scope.currentSection._id] = [];
					$scope.backups = [];
					$scope.searchFilterValue = '';
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: $scope.currentSection._id,
						account_id: $scope.accountData._id,
						limit: 9999999
					};

					api.listBackupForType({ 
						data: apiParams, 
						success: function (data) {
							$scope.loading = false;
	
							for(var i = 0; i < data.backups.length; i++) {
								data.backups[i].options = [];
								replaceItem(data.backups[i]);
							}
	
							$scope.selected.full_items = data.backups;

							checkFull($scope.currentSection._id);
							callback();
						},
						failed: function () {
							$scope.loading = false;
							callback();
						}
					});
				};

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.backupsFiltered = [];

					var records = [];
					if($scope.searchFilterValue) {
						for(var i = 0; i < $scope.list[$scope.currentSection._id].length; i++) {
							if(!(new RegExp($scope.searchFilterValue)).test($scope.list[$scope.currentSection._id][i].name)) continue;
							records.push($scope.list[$scope.currentSection._id][i]);
						}
					} else {
						records = $scope.list[$scope.currentSection._id];
					}

					metaAcct.setTotalItems(records.length);

					var skipped = 0;
					
					for(var i = 0; i < records.length; i++) {

						if($scope.backups.length >= metaAcct.getPageSize()) break;

						if(skipped < metaAcct.getSkip()) {
							skipped++;
							continue;
						}

						$scope.backups.push(records[i]);
					}

					metaAcct.calculate($scope.backups);
				};

				$scope.ok = function () { $uibModalInstance.close(); };

				$scope.changeSection = function (section) {
					$scope.currentSection = section;
					$scope.fetchReal(function () {
						//metaAcct.setTotalItems($scope.list[$scope.currentSection._id].length);
						$scope.static.isAllChecked = $scope.getChecked().length === metaAcct.getTotalItems();
						$scope.fetch();
					});
				};

				$scope.changeFullBackup = function() {
					if($scope.selected.full === '') return;
					$scope.uncheckAll();

					api.getBackupItems({ 
						data: { 
							_id: $scope.selected.full,
							limit: 999999
						}, 
						success: function(data) {
							if(!data.backups.length) return;
							$scope.selected.full_items = data.backups;
							checkFull();
						}
					});
				};

				$scope.calculateSummary = function() {

					var gotData = false;
					$scope.encryption.encrypted = false;
					$scope.list_checked = {};
					$scope.list_checked_parents = {};
					for(var contains in $scope.list) {
						for(var i = 0; i < $scope.list[contains].length; i++) {
							if($scope.list[contains][i].checked) {
								if(!$scope.encryption.encrypted && $scope.list[contains][i].encrypted) $scope.encryption.encrypted = true;
								if($scope.list_checked[contains] === undefined) $scope.list_checked[contains] = [];
								$scope.list_checked[contains].push($scope.list[contains][i]);

								if($scope.list_checked_parents[$scope.list[contains][i].parent_id] === undefined)
									$scope.list_checked_parents[$scope.list[contains][i].parent_id] = $scope.list[contains][i].created;

								gotData = true;
							}
						}
					}

					$scope.summary.enabled = gotData;
				};

				$scope.checkOwnerRequire = function () {
					if(!permissions.isRoot || !$scope.panelConfig.account_data.owner_id) {
						$scope.require.owner = false;
						return;
					}

					$scope.validateOwner($scope.panelConfig.account_data.owner_id, function (exists, account) {

						if(!account.root && $scope.options.reseller) exists = false;

						if(exists) {
							$scope.autocomplete.accountText = account.username;
							$scope.selectNewOwner(account);
						}
						$scope.require.owner = !exists;
					});
				};

				$scope.showSummary = function(type) {

					if(type === 'Restore') {
						$scope.getPanelConfig();
						$scope.options.suspend = $scope.panelConfig.account_data.suspended;
						$scope.options.reseller = $scope.panelConfig.account_data.reseller;
						$scope.options.exclude = [];
						$scope.checkOwnerRequire();
					}

					if(!$scope.checkOrphanConfig()) return;

					$scope.summary.type = type;
					$scope.calculateSummary();
				};

				$scope.gotItems = function(types) {
					var list = $scope.getCheckedAll();
					for(var i = 0; i < list.length; i++) {
						if(types.indexOf(list[i].backup_contains) >= 0) return true;
					}
					return false;
				};

				$scope.getPanelConfig = function() {
					var list = $scope.getCheckedAll();
					for(var i = 0; i < list.length; i++) {
						if(list[i].backup_contains === consts.BACKUP_TYPE_ACCOUNT_CONFIG) {
							$scope.panelConfig = list[i];
							return $scope.panelConfig;
						}
					}

					$scope.panelConfig = { account_data: {} };

					return null;
				};

				$scope.checkOrphanConfig = function() {
					if(!$scope.accountData.orphan) return true;
					if($scope.getPanelConfig() === null) {
						alert.error(lang.t("You must select \"Panel Configurations\" item in order to restore orphan account"));
						return false;
					}

					return true;
				};

				$scope.validateOwner = function(owner_id, callback) {
					if(callback === undefined) callback = function() {};
					api.getAccount({ 
						data: { _id: owner_id }, 
						success: function (data) {
							callback(data.reseller, data); 
						},
						failed: function () {
							callback(false, {});
						}
					});
				};

				$scope.exclude = { row: '' };

				$scope.validateListPath = function (path) {
					if(!path.trim()) return false;
					return !consts.PATH_FILTER_PATTERNS.test(path);
				};

				$scope.addExcludeRow = function () {
					if($scope.exclude.row === undefined || !$scope.exclude.row.trim()) return;
					if($scope.validateListPath($scope.exclude.row.trim())) $scope.options.exclude.push($scope.exclude.row.trim());
					else alert.error(lang.t('The provided path ("%s") is invalid. The path must start with a "/".', $scope.exclude.row.trim() ));
					$scope.exclude.row = '';

				};
				
				$scope.addMultiExcludeRow = function() {

					$scope.listTitle = lang.t("Directories and Files to exclude");
					$scope.listData = $scope.options.exclude.join("\n");

					$scope.listUIB = popup.open({
						template: 'listSelection',
						noController: true,
						scope: $scope
					});

					$scope.listUIB.result.then(function(records) {
						while($scope.options.exclude.length) $scope.options.exclude.pop();
						records = records.split("\n");
						var invalidPaths = [];
						for(var i = 0; i < records.length; i++) {
							if($scope.validateListPath(records[i])) {
								if ($scope.options.exclude.indexOf(records[i]) < 0 ) $scope.options.exclude.push(records[i]);
							} else invalidPaths.push(records[i]);
						}

						if(invalidPaths.length) alert.error(lang.t('The following paths ("%s") is invalid. The path must start with a "/" and can\'t have trailing "/"' + (type === 'include' ? ', also patterns are not allowed.' : '.'), invalidPaths.join(", ") ))
					}, function () {});
				};

				$scope.$watch('options.reseller', function() {

					$scope.getPanelConfig();

					if(!$scope.owner.root && $scope.options.reseller) {
						$scope.require.owner = true;
						$scope.resetNewOwner();
					}
				});

				$scope.restore = function() {

					if($scope.getPanelConfig() === null) {
						$scope.options.terminate = false;
						$scope.options.reseller = false;
						$scope.options.suspend = false;
						$scope.options.owner = '';
					}
					
					if(!$scope.checkOrphanConfig()) return;

					var liveAccount = !($scope.options.terminate || $scope.accountData.orphan);

					if(!liveAccount && $scope.require.owner && !$scope.options.owner) {
						alert.error(lang.t("You must select new owner"));
						return;
					}

					for(var i = 0; i < $scope.restore_conditions.length; i++) {
						var condition = $scope.restore_conditions[i];
						if($scope.conditions.restore[condition._id] === undefined || !$scope.conditions.restore[condition._id]) {
							alert.error(lang.t("Please accept all restore conditions"));
							return;
						}
					}

					if($scope.askForEncryptionKey() && !$scope.encryption.key) {
						alert.error(lang.t("You must provide \"Backups Private Encryption Key\""));
						return;
					}

					var list = $scope.getCheckedAll();
					var ids = [];
					for(var i = 0; i < list.length; i++) ids.push(list[i]._id);


					var options = util.duplicateObject($scope.options);

					if(liveAccount) {
						delete options.reseller;
						delete options.owner;
					} else {
						if(options.terminate) delete options.merge;
					}

					if(!permissions.isRoot) {
						delete options.reseller;
						delete options.owner;
					}
					
					if(!permissions.isReseller) {
						delete options.suspend;
					}

					api.addQueueItems({ 
						data: { 
							type: consts.QUEUE_ITEM_TYPE_RESTORE, 
							items: ids, 
							files: $scope.files, 
							options: options, 
							encryption_key: $scope.encryption.key 
						}, 
						success: function (data, message) {
							$scope.encryption.key = '';
							alert.success(message);
							$uibModalInstance.close();
							if($scope.summary.gotoqueue) $location.path("/queue");
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.download = function() {

					if($scope.askForEncryptionKey() && !$scope.encryption.key) {
						alert.error(lang.t("You must provide \"Backups Private Encryption Key\""));
						return;
					}

					var options = util.duplicateObject($scope.options);

					var list = $scope.getCheckedAll();
					var ids = [];
					for(var i = 0; i < list.length; i++) ids.push(list[i]._id);

					api.addQueueItems({ 
						data: { 
							type: consts.QUEUE_ITEM_TYPE_DOWNLOAD, 
							items: ids, files: $scope.files, 
							options: options, 
							encryption_key: $scope.encryption.key 
						}, 
						success: function (data, message) {
							$scope.encryption.key = '';
							alert.success(message);
							$uibModalInstance.close();
							if($scope.summary.gotoqueue) $location.path("/queue");
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.removeItems = function(contains) {

					$scope.selected.full = '';
					$scope.selected.full_items = [];

					for(var i = 0; i < $scope.list[contains].length; i++) {
						var backup = $scope.list[contains][i];
						backup.checked = false;
						if($scope.files[backup._id] !== undefined) delete $scope.files[backup._id];
					}
					$scope.calculateSummary();
				};

				$scope.removeSnapshot = function(id) {

					$scope.selected.full = '';
					$scope.selected.full_items = [];

					for(var contains in $scope.list) {
						for(var i = 0; i < $scope.list[contains].length; i++) {
							var backup = $scope.list[contains][i];
							if(backup.parent_id !== id) continue;
							backup.checked = false;
							if($scope.files[backup._id] !== undefined) delete $scope.files[backup._id];
						}
					}
					$scope.calculateSummary();
				};

				$scope.$watch('require', function () {
					var require = $scope.require.owner;
					$scope.localOptions.chown = require;
					$scope.chownDisabled = require;
				}, true);
				
				api.listRestoreConditions({ 
					data: { find: { disabled: false } }, 
					success: function (data) {
						$scope.restore_conditions = data.conditions;
					}
				});
				
				$scope.deleteSnapshot = function() {
					if(!$scope.selected.full) return;

					confirm.open({
						message: lang.t("Are you sure you want to delete this snapshot?"),
						confirm: function () {

							api.deleteSnapshot({
								data: {
									_id: $scope.selected.full
								},
								success: function (data, message) {
									$scope.reset();
									$scope.fetchFulls();
									$scope.changeSection($scope.sections[0]);
									alert.success(message);
								},
								failed: function (message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {
						}
					});
				};
				
				$scope.fetchFulls = function (callback) {
					if(callback === undefined || typeof callback !== 'function') callback = function(){};
					
					api.listBackupForTypeName({
						data: {
							name: $scope.accountData.username,
							type: consts.BACKUP_TYPE_ACCOUNT,
							contains: consts.BACKUP_TYPE_ACCOUNT_FULL,
							account_id: $scope.accountData._id,
							sort: { created: -1 },
							limit: 9999999
						},
						success: function (data) {

							for(var i = 0; i < data.backups.length; i++) {
								if(i === 0) $scope.selected.full = data.backups[i].parent_id;

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.fulls.push({ _id: data.backups[i].parent_id, display: lang.d(data.backups[i].created, 'shorttime') });
								$scope.fulls_list[data.backups[i].parent_id] = data.backups[i];
							}

							$scope.fulls.push({ _id: '', display: lang.t("Custom") });
							$scope.changeFullBackup();
							callback();
						}
					});
				};

				$scope.fetchFulls();
				$scope.changeSection($scope.sections[0]);

			}
		]
	);
});


define('controllers/accountDownloads',['app'], function(app) {
	
	app.controller("accountDownloads",
		["$uibModalInstance", "$rootScope", "$scope", "$location", "$timeout", "api", "meta", "util", "consts", "lang", "account", "alert",
			function ($uibModalInstance, $rootScope, $scope, $location, $timeout, api, meta, util, consts, lang, account, alert) {

				$scope.loading = false;
				$scope.account = account;
				$scope.downloads = [];

				meta = meta.new("account_downloads");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([5]);
				meta.setPageSize(5);
				meta.setSortFields(["created", "size"]);
				meta.setTotalItems($scope.downloads.length);

				$scope.close = function () { $uibModalInstance.close(); };

				$scope.directDownload = function(download) {
					window.location = window.PAGE.path.download + "&download_id=" + download._id;
				};

				$scope.saveNotes = function (download, keyEvent) {
					download.notes = download.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageDownloadNotes({ 
						data: { _id: download._id, notes: download.notes },
						success: function (data, message) {
							alert.success(message);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
					download.editing = false;
				};

				$scope.fetch = function () {

					if($scope.loading) return;
					$scope.loading = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter(),
						account_id: $scope.account._id
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.downloads = [];

					api.listDownloads({ 
						data: apiParams, 
						success: function(data) {
							$scope.loading = false;
							meta.setTotalItems(data.total);
							meta.calculate(data.downloads);
							$scope.downloads = data.downloads;
						}
					});

				};

				$timeout($scope.fetch());
			}
		]
	);
});


define('controllers/accountFilters',['app'], function(app) {
	app.controller("accountFilters",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "confirm", "consts", "lang", "alert",
			function ($rootScope, $scope, $location, $timeout, api, meta, confirm, consts, lang, alert) {
				$rootScope.$emit('menuItem', 'AccountFilters');

				$scope.filters = [];
				$scope.groups = {};
				$scope.loadingFilters = false;
				$scope.saveing = false;
				$scope.filter = 0;

				$scope.filterOptions = [
					{ label: lang.t("All Filter Types"), value: 0 },
					{ label: lang.t("Accounts Filter"), value: consts.ACCOUNT_FILTER_TYPE_ACCOUNT },
					{ label: lang.t("Account Tags Filter"), value: consts.ACCOUNT_FILTER_TYPE_ACCOUNT_TAG },
					{ label: lang.t("Owned By Filter"), value: consts.ACCOUNT_FILTER_TYPE_OWNEDBY },
					{ label: lang.t("Resellers Filter"), value: consts.ACCOUNT_FILTER_TYPE_RESELLER },
					{ label: lang.t("Suspension Filter"), value: consts.ACCOUNT_FILTER_TYPE_SUSPENSION },
					{ label: lang.t("Encryption Filter"), value: consts.ACCOUNT_FILTER_TYPE_ENCRYPTION },
					{ label: lang.t("Disk Space Usage Filter"), value: consts.ACCOUNT_FILTER_TYPE_DISK_USAGE },
					{ label: lang.t("Inodes Usage Filter"), value: consts.ACCOUNT_FILTER_TYPE_INODE_USAGE },
					{ label: lang.t("Packages Filter"), value: consts.ACCOUNT_FILTER_TYPE_PACKAGE },
					{ label: lang.t("Characters Range Filter"), value: consts.ACCOUNT_FILTER_TYPE_RANGE },
					{ label: lang.t("Regular Expression Filter"), value: consts.ACCOUNT_FILTER_TYPE_REGEX }
				];

				$scope.types = {};
				for(var i = 0; i < $scope.filterOptions.length; i++) if($scope.filterOptions[i].value > 0) $scope.types[$scope.filterOptions[i].value] = $scope.filterOptions[i].label;


				$scope.loaders = {
					delete: false
				};

				meta = meta.new("filters");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["name","type","owner"]);
				meta.setTotalItems($scope.filters.length);

				$scope.onClickDelete = function(filter) {

					if($scope.saveing) return;

					if(filter.groups_count > 0)
					{
						alert.error(lang.t("This filter has an assigned filter groups, Please remove those groups before deleting this filter."));
						return false;
					}

					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This filter will be permanently deleted!"),
						confirm: function () {

							api.deleteAccountFilter({ 
								data: { _id: filter._id }, 
								success: function(data, message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									$scope.fetch();
									alert.success(message);
								},
								failed: function (message) {
									$scope.saveing = false;
									$scope.loaders.delete = false;
									alert.error(message);
								}

							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.listGroups = function(callback) {

					api.listAccountFilterGroups({ 
						success: function(data) {

							for(var i = 0; i < data.groups.length; i++) {
								if($scope.groups[data.groups[i]._id] === undefined) $scope.groups[data.groups[i]._id] = [];
								$scope.groups[data.groups[i]._id].push(data.groups[i]);
							}

							if(callback !== undefined) callback();
						},
						failed: function () {
							if(callback !== undefined) callback();
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingFilters = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();
					if($scope.filter) apiParams.find.type = $scope.filter;

					$scope.filters = [];

					api.listAccountFilters({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.filters);
							$scope.filters = data.filters;
							for(var i = 0; i < $scope.filters.length; i++) $scope.groups[$scope.filters[i]._id] = [];
							$scope.listGroups(function () { $scope.loadingFilters = false; });
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers/accountFilterManage',['app'], function(app) {
	app.controller("accountFilterManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$q", "api", "lang", "util", "confirm", "consts", "alert", "permissions", "popup",
			function ($rootScope, $scope, $routeParams, $location, $timeout, $q, api, lang, util, confirm, consts, alert, permissions, popup) {
				$rootScope.$emit('menuItem', 'AccountFilters');

				$scope.details = {
					name: '',
					owner: $scope.loggedAccount._id,
					owner_name: $scope.loggedAccount.username
				};

				$scope.saveData = util.duplicateObject($scope.details);
				$scope.autocomplete = { accountText: $scope.saveData.owner_name };

				$scope.saveing = false;
				$scope.changed = false;
				$scope.cancelled = false;
				$scope.range = "0123456789_abcdefghijklmnopqrstuvwxyz";
				$scope.tags = {};
				$scope.item = { package: '' };
				$scope.accounts = {};

				$scope.conditions = [
					{ label: lang.t("Include"), value: consts.ACCOUNT_FILTER_CONDITION_INCLUDE },
					{ label: lang.t("Exclude"), value: consts.ACCOUNT_FILTER_CONDITION_EXCLUDE }
				];

				$scope.types = [
					{ label: lang.t("Accounts Filter"), value: consts.ACCOUNT_FILTER_TYPE_ACCOUNT, template: 'account' },
					{ label: lang.t("Owned By Filter"), value: consts.ACCOUNT_FILTER_TYPE_OWNEDBY, template: 'reseller' },
					{ label: lang.t("Resellers Filter"), value: consts.ACCOUNT_FILTER_TYPE_RESELLER, template: 'reseller' },
					{ label: lang.t("Suspension Filter"), value: consts.ACCOUNT_FILTER_TYPE_SUSPENSION, template: 'suspension' },
					{ label: lang.t("Encryption Filter"), value: consts.ACCOUNT_FILTER_TYPE_ENCRYPTION, template: 'encryption' },
					{ label: lang.t("Disk Space Usage Filter"), value: consts.ACCOUNT_FILTER_TYPE_DISK_USAGE, template: 'diskusage' },
					{ label: lang.t("Inodes Usage Filter"), value: consts.ACCOUNT_FILTER_TYPE_INODE_USAGE, template: 'inodeusage' },
					{ label: lang.t("Packages Filter"), value: consts.ACCOUNT_FILTER_TYPE_PACKAGE, template: 'package' },
					{ label: lang.t("Characters Range Filter"), value: consts.ACCOUNT_FILTER_TYPE_RANGE, template: 'range' },
					{ label: lang.t("Regular Expression Filter"), value: consts.ACCOUNT_FILTER_TYPE_REGEX, template: 'regex' }
				];

				if(permissions.isRoot) $scope.types.push({ label: lang.t("Account Tags Filter"), value: consts.ACCOUNT_FILTER_TYPE_ACCOUNT_TAG, template: 'accounttags' });

				$scope.selectCreator = function(account) {
					if(account === undefined) return;
					$scope.saveData.owner = account._id;
					$scope.saveData.owner_name = account.username;
					$scope.autocomplete.accountText = account.username;
					var activeElement = document.activeElement;
					if (activeElement) activeElement.blur();
				};

				$scope.searchCreators = function(query) {
					if(query) {
						var deferred = $q.defer();
						api.listAccounts({ 
							data: { login_only: 1, filter: query, sort: { username: 1 } }, 
							success: function(data) {
								var results = [];
								for(var i = 0; i < data.accounts.length; i++) results.push(data.accounts[i]);
								deferred.resolve( results );
							}
						});

						return deferred.promise;
					}

					return [];
				};

				$scope.loadFilterType = function(type, defaults) {

					$scope.saveData = util.duplicateObject($scope.details);
					$scope.autocomplete.accountText = $scope.saveData.owner_name;

					if(defaults)
					{
						$scope.saveData.condition = consts.ACCOUNT_FILTER_CONDITION_INCLUDE;
						$scope.saveData.type = type;

						switch(type)
						{
							case consts.ACCOUNT_FILTER_TYPE_ACCOUNT:
							case consts.ACCOUNT_FILTER_TYPE_ACCOUNT_TAG:
							case consts.ACCOUNT_FILTER_TYPE_RESELLER:
							case consts.ACCOUNT_FILTER_TYPE_OWNEDBY:
							case consts.ACCOUNT_FILTER_TYPE_PACKAGE:
								$scope.saveData.list = [];
							break;

							case consts.ACCOUNT_FILTER_TYPE_INODE_USAGE:
							case consts.ACCOUNT_FILTER_TYPE_DISK_USAGE:
								$scope.saveData.usage = 0;
							break;

							case consts.ACCOUNT_FILTER_TYPE_RANGE:
								$scope.saveData.range_start = '0';
								$scope.saveData.range_end = 'z';
							break;

							case consts.ACCOUNT_FILTER_TYPE_REGEX:
								$scope.saveData.regex = '';
							break;
						}
					}

					if($scope.saveData.type == consts.ACCOUNT_FILTER_TYPE_DISK_USAGE || $scope.saveData.type == consts.ACCOUNT_FILTER_TYPE_INODE_USAGE)
					{
						$scope.conditions[0].label = lang.t("Include Below (or equals)");
						$scope.conditions[1].label = lang.t("Include Above (or equals)");
					}
					else
					{
						$scope.conditions[0].label = lang.t("Include");
						$scope.conditions[1].label = lang.t("Exclude");
					}

					for(var i = 0; i < $scope.types.length; i++) {
						if($scope.types[i].value === type) {
							$scope.filterType = $scope.includePath('accountFilters/' + $scope.types[i].template);
							return;
						}
					}

				};

				$scope.itemsSelection = function () {

					var types = {};
					types[consts.ACCOUNT_FILTER_TYPE_ACCOUNT] = { size: 'lg', template: 'accountsSelection', resolve: { accounts: function() { return $scope.saveData.list; }, includeOrphan: function () { return 0; }, callParams: function () { return ''; } } };
					types[consts.ACCOUNT_FILTER_TYPE_RESELLER] = { size: 'lg', template: 'accountsSelection', controller: 'resellersSelection', resolve: { accounts: function() { return $scope.saveData.list; }, includeOrphan: function () { return 0; } } };
					types[consts.ACCOUNT_FILTER_TYPE_OWNEDBY] = { size: 'lg', template: 'accountsSelection', controller: 'resellersSelection', resolve: { accounts: function() { return $scope.saveData.list; }, includeOrphan: function () { return 0; } } };
					types[consts.ACCOUNT_FILTER_TYPE_PACKAGE] = { size: 'lg', template: 'accountPackagesSelection', resolve: { packages: function() { return $scope.saveData.list; }, account: function () { return null; } } };
					types[consts.ACCOUNT_FILTER_TYPE_ACCOUNT_TAG] = { size: 'lg', template: 'tagsSelection', resolve: { tags: function() { return $scope.saveData.list; }, type: function () { return consts.TAG_TYPE_ACCOUNT; } } };

					popup.open(types[$scope.saveData.type]).result.then(function(selected) {
						$scope.saveData.list = selected;
					}, function () {});
				};

				$scope.searchTags = function(query) {

					if(!query) return [];

					var deferred = $q.defer();

					api.listTags({ 
						data: { filter: query, sort: { name: 1 }, find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function(data) {
							var results = [];
							for(var i = 0; i < data.tags.length; i++) {
								var tag = data.tags[i];
								if($scope.saveData.list.indexOf(tag._id) >= 0) continue;
								results.push(tag);
							}
							deferred.resolve( results );
						},
						failed: function (message) {
							
						}
					});

					return deferred.promise;
				};

				$scope.searchAccountPackages = function(query) {
					if(!query) return [];

					var deferred = $q.defer();

					api.listAccountPackages({ 
						data: { all: 1, filter: query, sort: { name: 1 } }, 
						success: function(data) {
							var results = [];
							for(var i = 0; i < data.packages.length; i++) {
								var packageData = data.packages[i];
								if($scope.saveData.list.indexOf(packageData.name) >= 0) continue;
								results.push(packageData);
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.searchAccounts = function(query) {

					if(!query) return [];

					var reseller = $scope.saveData.type === consts.ACCOUNT_FILTER_TYPE_RESELLER || $scope.saveData.type === consts.ACCOUNT_FILTER_TYPE_OWNEDBY;
					var deferred = $q.defer();

					api.listAccounts({ 
						data: { filter: query, sort: { username: 1 } }, 
						success: function(data) {

							var results = [];
							for(var i = 0; i < data.accounts.length; i++) {
	
								var account = data.accounts[i];
	
								if(
									(!reseller && $scope.saveData.list.indexOf(account.username) >= 0)
									||
									(reseller && (!account.reseller || $scope.saveData.list.indexOf(account.username) >= 0))
								) continue;
	
								results.push(account);
							}
							deferred.resolve( results );
						}
					});

					return deferred.promise;
				};

				$scope.addPackage = function() {
					var value = $scope.item.package.trim();

					if(!value) return;
					if($scope.saveData.list.indexOf(value) >= 0) {
						$scope.item.package = '';
						return;
					}

					$scope.saveData.list.push(value);
					$scope.item.package = '';
				};

				$scope.addMultiplePackages = function() {

					$scope.listData = $scope.saveData.list.join("\n");
					
					$scope.listUIB = popup.open({
						template: 'listSelection',
						scope: $scope,
						noController: true
					});
					
					$scope.listUIB.result.then(function(records) {
						while($scope.saveData.list.length) $scope.saveData.list.pop();

						records = records.split("\n");

						for(var i = 0; i < records.length; i++) {
							if($scope.saveData.list.indexOf(records[i]) >= 0) continue;
							$scope.saveData.list.push(records[i]);
						}
					}, function () {});

				};

				$scope.selectItem = function(item) {
					if(item === undefined) return;
					$scope.saveData.list.push(item);
					$scope.autocomplete.filterText = '';
				};

				$scope.rangeStartValueCheck = function (char) {
					return char <= $scope.saveData.range_end;
				};

				$scope.rangeEndValueCheck = function (char) {
					return char >= $scope.saveData.range_start;
				};

				$scope.fetchFilterData = function(filter_id) {
					api.getAccountFilter({ 
						data: { _id: filter_id }, 
						success: function(data) {
							$scope.details = data;
	
							if($scope.details.type == consts.ACCOUNT_FILTER_TYPE_DISK_USAGE && $scope.details.usage > 0) {
								$scope.details.usage = (($scope.details.usage / 1024) / 1024);
							}
	
							$scope.loadFilterType($scope.details.type);
						}
					});
				};

				$scope.$watch("saveData", function(){
					$scope.changed = util.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('createFilter', function () {
					$scope.saveChanges(true, function(response) {
						$scope.$emit('filterResponse', response);
					});
				});

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled && !$scope.popup && !$scope.wizardData) {
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/accountFilters');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = util.saveParams($scope.saveData, $scope.details, [], function(key) {
						return ($scope.details._id === undefined && key === 'type');
					});

					apiParams.action = $scope.details._id ? 'modify' : 'create';

					if(apiParams.usage !== undefined && $scope.saveData.type == consts.ACCOUNT_FILTER_TYPE_DISK_USAGE && apiParams.usage > 0) {
						apiParams.usage = ((apiParams.usage * 1024) * 1024);
					}

					api.manageAccountFilter({ 
						data: apiParams, 
						success: function(data, message) {

							$scope.saveing = false;
	
							if(callback !== undefined && typeof callback === 'function') {
								callback({ success: true, data: data, message: message });
								return;
							}
	
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = util.duplicateObject($scope.saveData);
							if(apply) $location.path('/accountFilterManage/' + data._id);
							else $location.path('/accountFilters');
	
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;

							if(callback !== undefined && typeof callback === 'function') {
								callback({ success: false, data: {}, message: message });
								return;
							}
							
							alert.error(message);
						}
					});
				};

				$scope.loadAccounts = function () {
					api.listAccounts({
						success: function(data) {
							for(var i = 0; i < data.accounts.length; i++) {
								$scope.accounts[data.accounts[i].username] = data.accounts[i];	
							}
						}
					});
				};
				
				$scope.loadData = function () {
					var filter_id = $routeParams.id;
					if(filter_id) $timeout($scope.fetchFilterData(filter_id));
					else $scope.loadFilterType(consts.ACCOUNT_FILTER_TYPE_ACCOUNT, true);
					$scope.loadAccounts();
				};

				if(permissions.isRoot) {
					api.listTags({ 
						data: { find: { type: consts.TAG_TYPE_ACCOUNT } }, 
						success: function (data) {
							for(var i = 0; i < data.tags.length; i++) $scope.tags[data.tags[i]._id] = data.tags[i];
							$scope.loadData();
						}
					});
				} else {
					$scope.loadData();
				}
	}]);
});


define('controllers/accountFilterManagePopup',['app'], function(app) {
	app.controller('accountFilterManagePopup',
		["$uibModalInstance", "$routeParams", "$rootScope", "$scope", "api", "consts", "lang", "alert",
			function($uibModalInstance, $routeParams, $rootScope, $scope, api, consts, lang, alert) {

				$scope.popup = true;
				$routeParams.id = null;

				$scope.details = {
					name: ''
				};

				$scope.saveData = {
					name: '',
					type: consts.ACCOUNT_FILTER_TYPE_ACCOUNT,
					list: [],
					condition: consts.ACCOUNT_FILTER_CONDITION_INCLUDE
				};

				$scope.$on('filterResponse', function (event, response) {

					if(!response.success) {
						alert.error(response.message);
						return;
					}

					api.getAccountFilterGroup({ 
						data: { _id: response.data.group_id }, 
						success: function(data) {
							alert.success(response.message);
							$uibModalInstance.close(data);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				});

				$scope.ok = function () {
					$rootScope.$broadcast('createFilter');
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss();
				};
	}]);

});


define('controllers/accountFilterGroupManage',['app'], function(app) {
	app.controller("accountFilterGroupManage",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "api", "consts", "lang", "meta", "utils", "alert", "confirm",
			function ($rootScope, $scope, $routeParams, $location, $timeout, api, consts, lang, meta, utils, alert, confirm) {
				$rootScope.$emit('menuItem', 'AccountFilters');

				$scope.details = {
					name: '',
					filters: []
				};

				$scope.saveData = utils.duplicateObject($scope.details);

				$scope.filters = {};

				$scope.saveing = false;
				$scope.changed = false;

				$scope.types = {};
				$scope.types[consts.ACCOUNT_FILTER_TYPE_ACCOUNT] = lang.t("Accounts Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_OWNEDBY] = lang.t("Owned By Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_RESELLER] = lang.t("Resellers Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_SUSPENSION] = lang.t("Suspension Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_ENCRYPTION] = lang.t("Encryption Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_DISK_USAGE] = lang.t("Disk Space Usage Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_INODE_USAGE] = lang.t("Inodes Usage Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_PACKAGE] = lang.t("Packages Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_RANGE] = lang.t("Characters Range Filter");
				$scope.types[consts.ACCOUNT_FILTER_TYPE_REGEX] = lang.t("Regular Expression Filter");

				$scope.toggleFilter = function (filter) {
					var idx = $scope.saveData.filters.indexOf(filter._id);
					if (idx > -1) $scope.saveData.filters.splice(idx, 1);
					else $scope.saveData.filters.push(filter._id);
				};

				$scope.fetchGroupData = function(group_id) {
					api.getAccountFilterGroup({ 
						data: { _id: group_id }, 
						success: function(data) {
							$scope.details = data;
							$scope.saveData = utils.duplicateObject($scope.details);
						}
					});
				};

				$scope.$watch("saveData", function(){
					$scope.changed = utils.isChanged($scope.saveData, $scope.details, ['_id']);
				}, true);

				$scope.$on('createFilter', function (event) {
					$scope.saveChanges(true, function(response) {
						$scope.$emit('filterResponse', response);
					});
				});

				$scope.$on('$destroy', function() {
					if($scope.changed && !$scope.cancelled) {
						confirm.open({
							message: lang.t("You didn't saved your changes"),
							confirm: $scope.saveChanges,
							cancelLabel: lang.t("Disregard Changes"),
							confirmLabel: lang.t("Save"),
						});
					}
				});

				$scope.cancel = function() {
					$scope.cancelled = true;
					$location.path('/accountFilterGroups');
				};

				$scope.saveChanges = function(apply, callback) {

					if($scope.saveing) return;

					$scope.saveing = true;

					var apiParams = utils.saveParams($scope.saveData, $scope.details);
					apiParams.action = $scope.details._id ? 'modify' : 'create';

					api.manageAccountFilterGroup({ 
						data: apiParams, 
						success: function(data, message) {

							$scope.saveing = false;
	
							if(callback !== undefined) {
								callback({ success: true, data: data, message: message });
								return;
							}
							
							$scope.changed = false;
							$scope.saveData._id = data._id;
							$scope.details = utils.duplicateObject($scope.saveData);
							if(apply) $location.path('/accountFilterGroupManage/' + data._id);
							else $location.path('/accountFilterGroups');
	
							alert.success(message);
						},
						failed: function (message) {
							$scope.saveing = false;

							if(callback !== undefined) {
								callback({ success: false, data: {}, message: message });
								return;
							}

							alert.error(message);
						}
					});
				};

				$scope.fetchFilters = function (callback) {

					$scope.filters = {};
					api.listAccountFilters({ 
						success: function (data) {
							for(var i = 0; i < data.filters.length; i++) {
								$scope.filters[data.filters[i]._id] = data.filters[i];
							}
							if(callback !== undefined) callback();
						}
					});
				};

				$timeout($scope.fetchFilters(function() {
					var group_id = $routeParams.id;
					if(group_id) $timeout($scope.fetchGroupData(group_id));
				}));
			}
		]
	);
});


define('controllers/accountFilterGroupManagePopup',['app'], function(app) {
	app.controller('accountFilterGroupManagePopup',
		["$uibModalInstance", "$rootScope", "$scope", "api", "lang", "alert",
			function($uibModalInstance, $rootScope, $scope, api, lang, alert) {

				$scope.saveData = {
					name: '',
					filters: []
				};

				$scope.$on('filterResponse', function (event, response) {

					if(!response.success) {
						alert.error(response.message);
						return;
					}

					api.getAccountFilterGroup({ 
						data: { _id: response.data._id }, 
						success: function(data) {
							alert.success(response.message);
							$uibModalInstance.close(data);
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				});

				$scope.ok = function () {
					$rootScope.$broadcast('createFilter');
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss();
				};
	}]);

});


define('controllers/accountFilterGroups',['app'], function(app) {
	app.controller("accountFilterGroups",
		["$rootScope", "$scope", "$location", "$timeout", "api", "meta", "confirm", "lang",
			function ($rootScope, $scope, $location, $timeout, api, meta, confirm, lang) {
				$rootScope.$emit('menuItem', 'AccountFilters');

				$scope.groups = [];
				$scope.filters = {};
				$scope.loadingGroups = false;
				$scope.saveing = false;

				$scope.loaders = {
					delete: false
				};

				meta = meta.new("filter_groups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				if(!meta.getSortBy()) meta.setSortBy("name");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setSortFields(["name","type","owner","count"]);
				meta.setTotalItems($scope.groups.length);

				$scope.onClickDelete = function(group) {

					if($scope.saveing) return;

					if(group.count > 0)
					{
						alert.error(lang.t("This account filter group has an assigned jobs, Please remove those jobs before deleting this account filter group."));
						return false;
					}

					$scope.saveing = true;
					$scope.loaders.delete = true;

					confirm.open({
						message: lang.t("This group will be permanently deleted!"),
						confirm: function () {

							api.deleteAccountFilterGroup({ _id: group._id }, function(response) {

								$scope.saveing = false;
								$scope.loaders.delete = false;

								if(response.success) {
									$scope.fetchData();
									alert.success(response.message);
									return;
								}

								alert.error(response.message);
							});
						},
						cancel: function () {
							$scope.saveing = false;
							$scope.loaders.delete = false;
						}
					});
				};

				$scope.fetchFilters = function (callback) {

					$scope.filters = {};
					api.listAccountFilters({ 
						success: function (data) {
							for(var i = 0; i < data.filters.length; i++) {
								$scope.filters[data.filters[i]._id] = data.filters[i];
							}
							if(callback !== undefined) callback();
						}
					});
				};

				$scope.fetch = function() {

					$scope.loadingGroups = true;

					var apiParams = {
						sort: {},
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						find: {},
						filter: meta.getFilter()
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					$scope.groups = [];

					api.listAccountFilterGroups({ 
						data: apiParams, 
						success: function(data) {
							meta.setTotalItems(data.total);
							meta.calculate(data.groups);
							$scope.groups = data.groups;
							$scope.loadingGroups = false;
						}
					});
				};

				$timeout($scope.fetchFilters(function() {
					$scope.fetch();
				}));
			}
		]
	);
});


define('controllers/accountFilterGroupSelection',['app'], function(app) {

	app.controller('accountFilterGroupSelection',
		["$uibModalInstance", "$scope", "filters", "details", "alert", "lang", "popup",
			function($uibModalInstance, $scope, filters, details, alert, lang, popup) {

		$scope.filters = [];
		$scope.allFilters = filters;

		$scope.newFilter = function () {

			popup.open({
				size: "lg",
				template: 'accountFilterManagePopup',
				scope: $scope,
			}).result.then(function(filterDetails) {

				if(!filterDetails._id)
				{
					alert.error(lang.t("Failed to create filter"));
					return;
				}

				$scope.allFilters[filterDetails._id] = filterDetails;
				$scope.selectedFilter = filterDetails._id;
				$scope.ok();
				/*
				//$scope.allFilters[filterDetails._id] = filterDetails;
				$scope.allFilters[filterDetails._id] = filterDetails;
				$scope.setFilters();
				*/

			}, function () {
				//$log.info('Modal dismissed at: ' + new Date());
			});

		};

		$scope.setFilters = function () {
			for(var i in $scope.allFilters) {
				$scope.filters.push($scope.allFilters[i]);
			}
		};

		$scope.setFilters();

		$scope.selectedFilter = $scope.filters.length ? $scope.filters[0]._id : '';

		$scope.ok = function () {
			$uibModalInstance.close( $scope.selectedFilter );
		};

		$scope.cancel = function () {
			$uibModalInstance.dismiss(lang.t('cancel'));
		};
	}]);

});


define('controllers/accountsSelection',['app'], function(app) {
	app.controller('accountsSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "meta", "accounts", "includeOrphan", "callParams", "lang",
			function($uibModalInstance, $scope, $timeout, api, meta, accounts, includeOrphan, callParams, lang) {

				$scope.loading = false;
				$scope.accounts = [];

				$scope.fetchAccounts = function () {
					$scope.loading = true;

					api.listAccounts({ 
						data: { include_orphan: includeOrphan, sort: { username: 1 }, limit: 9999999 },
						success: function (data) {
							for (var i = 0; i < data.accounts.length; i++) {
								data.accounts[i].checked = accounts !== undefined && accounts.length ? accounts.indexOf(data.accounts[i].username) >= 0 : false;
							}
							$scope.accounts = data.accounts;
							$scope.loading = false;
						}
					});

				};

				$timeout($scope.fetchAccounts);

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.accounts.length; i++) {
						if($scope.accounts[i].checked) selected.push($scope.accounts[i].username);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/accountPackagesSelection',['app'], function(app) {
	app.controller('accountPackagesSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "meta", "packages", "account", "lang",
			function($uibModalInstance, $scope, $timeout, api, meta, packages, account, lang) {

				$scope.loading = false;
				$scope.packages = [];

				$scope.fetchAccountPackages = function () {
					if($scope.loading) return;
					$scope.loading = true;
					$scope.packages = [];

					var apiParams = {all: 1, sort: { name: 1 }};
					if(account) apiParams._id = account._id;

					var added = [];
					api.listAccountPackages({ 
						data: apiParams, 
						success: function (data) {
							for (var i = 0; i < data.packages.length; i++) {
								data.packages[i].checked = packages !== undefined && packages.length ? packages.indexOf(data.packages[i].name) >= 0 : false;
								
								if(added.indexOf(data.packages[i].name) < 0) {
									$scope.packages.push(data.packages[i]);
									added.push(data.packages[i].name);
								}
							}
							
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchAccountPackages);

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.packages.length; i++) {
						if($scope.packages[i].checked) selected.push($scope.packages[i].name);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/resellersSelection',['app'], function(app) {
	app.controller('resellersSelection',
		["$uibModalInstance", "$scope", "$timeout", "api", "meta", "lang", "accounts",
			function($uibModalInstance, $scope, $timeout, api, meta, lang, accounts) {

				$scope.loading = false;
				$scope.accounts = [];

				$scope.fetchAccounts = function () {

					$scope.loading = true;

					api.listAccounts({
						data: { limit: 9999999, find: { reseller: true } },
						success: function (data) {
							for (var i = 0; i < data.accounts.length; i++) {
								data.accounts[i].checked = accounts !== undefined && accounts.length ? accounts.indexOf(data.accounts[i].username) >= 0 : false;
								$scope.accounts.push(data.accounts[i]);
							}
	
							$scope.loading = false;
						}
					});
				};

				$timeout($scope.fetchAccounts);

				$scope.ok = function () {

					var selected = [];
					for (var i = 0; i < $scope.accounts.length; i++) {
						if($scope.accounts[i].checked) selected.push($scope.accounts[i].username);
					}
					$uibModalInstance.close( selected );
				};

				$scope.cancel = function () {
					$uibModalInstance.dismiss(lang.t('cancel'));
				};
			}
		]
	);
});


define('controllers/confirm',['app'], function(app) {

	app.controller('confirm',
		["$uibModalInstance", "$scope", "$timeout", "$sce", "api", "lang", "meta", "title", "message", "buttons", "labels",
			function($uibModalInstance, $scope, $timeout, $sce, api, lang, meta, title, message, buttons, labels) {

				$scope.title = title;
				$scope.message = $sce.trustAsHtml(message);
				$scope.buttons = buttons;
				$scope.labels = labels;
				$scope.close = function () { $uibModalInstance.close(); };
				$scope.dismiss = function () { $uibModalInstance.dismiss(); };
			}
		]
	);
});
define('controllers_enduser/dashboard',[
	'app',
], function(app) {
	app.controller("dashboard_enduser",
		["$rootScope", "$scope", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "confirm",
			function($rootScope, $scope, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, confirm) {

				$rootScope.$emit('menuItem', 'Dashboard');

				$scope.stats = {
					alerts: 0,
					accounts: 0,
					jobs: 0,
					backups: 0,
					over_quota: 0,
					jobs_running: 0
				};

				$scope.loadingStatistics = true;
				
				$scope.createBackupOnDemand = function () {

					confirm.open({
						message: lang.t("Are you sure you want to create backup on demand?"),
						confirm: function () {

							api.createBackupOnDemand({
								data: { account_id: $scope.loggedAccount._id },
								success: function(data, message) {
									alert.success(message);
								},
								failed: function(message) {
									alert.error(message);
								}
							});
						},
						cancel: function () {}
					});

				};
				
				$scope.fetch = function(callback) {

					if(callback === undefined | typeof callback !== 'function') callback = function() {};

					api.getDashboardDetails({
						success: function(data) {
							$scope.stats.alerts = data.statistics.total_new_alerts;
							$scope.stats.accounts = data.statistics.total_accounts;
							$scope.stats.backups = data.statistics.total_account_backups;
							$scope.stats.disk_usage = data.statistics.total_disk_usage;
							$scope.loadingStatistics = false;
							callback();
						},
						failed: function (message) {
							alert.error(message);
							$scope.loadingStatistics = false;
							callback();
						}
					});
				};

				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore',[
	'app',
], function(app) {
	app.controller("restore_enduser",
		["$rootScope", "$scope", "$routeParams", "$window", "$location", "$timeout", "$interval", "api", "meta", "lang", "popup", "permissions", "consts",
			function($rootScope, $scope, $routeParams, $window, $location, $timeout, $interval, api, meta, lang, popup, permissions, consts) {

				$rootScope.$emit('menuItem', 'Restore');
				
				$scope.currentSection = {};
				$scope.selected = {};
				$scope.sectionTemplate = '';
				$scope.sections = [
					{_id: 'full', name: lang.t("Full Account"), icon: 'fa-cubes', hidden: !permissions.canManageFullBackups},
					{_id: 'files', name: lang.t("Home Directory"), icon: 'fa-folder', hidden: !permissions.canManageFileBackups},
					{_id: 'cron', name: lang.t("Cron Jobs"), icon: 'fa-user-clock', hidden: !permissions.canManageCronBackups},
					{_id: 'db', name: lang.t("Databases"), icon: 'fa-database', hidden: !permissions.canManageDatabaseBackups},
					{_id: 'dbuser', name: lang.t("Database Users"), icon: 'fa-user-tie', hidden: !permissions.canManageDatabaseBackups},
					{_id: 'dns', name: lang.t("Domains"), icon: 'fa-map-marker-alt', hidden: !permissions.canManageDNSZoneBackups},
					{_id: 'ssl', name: lang.t("Certificates"), icon: 'fa-lock', hidden: !permissions.canManageCertificateBackups},
					{_id: 'email', name: lang.t("Email Accounts"), icon: 'fa-envelope', hidden: !permissions.canManageEmailBackups},
					{_id: 'ftp', name: lang.t("FTP Accounts"), icon: 'fa-file', hidden: !permissions.canManageFTPBackups}
				];

				$scope.saveNotes = function (backup, keyEvent) {
					backup.notes = backup.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageBackupNotes({
						data: { _id: backup._id, notes: backup.notes },
						success: function (data, message) { alert.success(message); },
						failed: function (message) { alert.error(message); },
					});
					backup.editing = false;
				};

				$scope.isSelected = function () {
					for(var id in $scope.selected) return true;
					return false;
				};

				$scope.isSelectedBackup = function (backup) {
					return $scope.selected[backup._id] !== undefined;
				};

				$scope.selectedBackup = function(backup) {
					if($scope.selected[backup._id] !== undefined) delete $scope.selected[backup._id];
					else $scope.selected[backup._id] = backup;
				};

				$scope.prepareSummary = function (type) {
					var backups = [];
					for(var id in $scope.selected) backups.push($scope.selected[id]);
					$scope.showSummary(type, backups);
				};

				$scope.changeBackup = function(backup) {

					backup.options = [];

					if(backup.new_id === backup._id) {
						backup.options_real = {};
						backup.new_id = '';
						return;
					}

					var oldId = backup._id;
					
					var newBackup = backup.options_real[backup.new_id];
					for(var key in newBackup) backup[key] = newBackup[key];

					if($scope.selected[oldId] !== undefined) {
						delete $scope.selected[oldId];
						$scope.selected[backup._id] = backup;
					}

					backup.options_real = {};
					backup.new_id = '';
				};

				$scope.selectBackup = function(backup) {

					backup.new_id = backup._id;
					backup.options = [];
					backup.options_real = {};

					var apiParams = {
						account_id: backup.account_id,
						type: backup.backup_type,
						contains: backup.backup_contains,
						name: backup.name,
						sort: { created: -1 },
						limit: 9999999
					};

					if(backup.params.engine !== undefined) apiParams.engine = backup.params.engine;
					
					api.listBackupForTypeName({
						data: apiParams,
						success: function (data) {
							for(var i = 0; i < data.backups.length; i++) {
								backup.options.push({ _id: data.backups[i]._id, display: lang.d(data.backups[i].created, 'shorttime') });
								backup.options_real[data.backups[i]._id] = data.backups[i];
							}
						}
					});
				};

				$scope.isTooltipEnabled = function() {
					return $window.innerWidth <= 928;
				};
				
				$scope.showSummary = function (type, items, files) {
					popup.open({
						size: "xl",
						template: 'backups',
						templateViews: 'views_enduser',
						controller: 'backups_enduser',
						resolve: {
							section: function () { return $scope.currentSection; },
							summary: function () { return type; },
							items: function() { return items; },
							files: function () { return files !== undefined ? files : {}; }
						}
					}).result.then(function(refresh) {
						if(refresh) $scope.fetch();
					}, function(){});
				};

				$scope.changeSection = function (section) {
					$scope.changeView('restore/' + section._id);
				};
				
				$scope.loadSection = function (type) {
					for(var i = 0; i < $scope.sections.length; i++) {
						var section = $scope.sections[i];
						if(section._id !== type || section.hidden) continue;
						$scope.currentSection = section;
						$scope.sectionTemplate = $scope.includePath('restore/' + section._id, 'views_enduser');
						return;
					}

					for(var i = 0; i < $scope.sections.length; i++) {
						var section = $scope.sections[i];
						if(section.hidden) continue;
						$scope.currentSection = section;
						$scope.sectionTemplate = $scope.includePath('restore/' + section._id, 'views_enduser');
						return;
					}
				};
				
				$scope.loadSection($routeParams.type);
			}
		]
	);
});
define('controllers_enduser/restore/full',[
	'app',
], function(app) {
	app.controller("restore_full_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert) {

				$scope.backups = [];
				$scope.selected = '';

				meta = meta.new("enduser_full_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.selectedBackup = function(backup) {
					if($scope.selected === backup.parent_id) $scope.selected = '';
					else $scope.selected = backup.parent_id;
				};

				$scope.prepareSummary = function (type) {
					api.getBackupItems({
						data: {
							_id: $scope.selected,
							limit: 999999
						},
						success: function (data) {
							$scope.showSummary(type, data.backups);
						},
						failed: function (message) {
							alert.error(message);
						}
					})
				};

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = '';
					
					var apiParams = {
						name: $scope.loggedAccount.username,
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_FULL,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForTypeName({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/files',[
	'app',
], function(app) {
	app.controller("restore_files_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {_id:''};
				$scope.files = undefined;
				
				meta = meta.new("enduser_files_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.selectedBackup = function(backup) {
					$scope.files = undefined;
					if($scope.selected._id !== backup._id) $scope.selected = backup;
					else $scope.selected = {_id:''};
				};

				$scope.totalFiles = function() {
					if($scope.files === undefined) return null;
					var output = 0;
					for(var path in $scope.files) output++;
					if(!output) return null;
					return output;
				};

				$scope.fileBrowse = function() {
					popup.open({
						size: "xl",
						template: 'fileManagerPopup',
						scope: $scope,
						resolve: {
							files: function() { return $scope.files; },
							backup: function() { return $scope.selected; }
						}
					}).result.then(function(files) {
						var total = 0;
						for(var path in files) total++;
						$scope.files = total ? files : undefined;
					}, function(){});
				};

				$scope.prepareSummary = function (type) {
					var files = {};
					if($scope.files !== undefined) files[$scope.selected._id] = $scope.files;
					$scope.showSummary(type, [$scope.selected], files);
				};

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {_id:''};
					$scope.files = undefined;
					
					var apiParams = {
						name: $scope.loggedAccount.username,
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_HOMEDIR,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForTypeName({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/cron',[
	'app',
], function(app) {
	app.controller("restore_cron_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {_id:''};
				$scope.files = {};
				
				meta = meta.new("enduser_cron_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.saveNotes = function (backup, keyEvent) {
					backup.notes = backup.notes.substr(0, 40);
					if(keyEvent && keyEvent.which !== 13) return;
					api.manageBackupNotes({
						data: { _id: backup._id, notes: backup.notes },
						success: function (data, message) { alert.success(message); },
						failed: function (message) { alert.error(message); },
					});
					backup.editing = false;
				};

				$scope.selectedBackup = function(backup) {
					if($scope.selected._id === backup._id) $scope.selected = {_id:''};
					else $scope.selected = backup;
				};

				$scope.prepareSummary = function (type) {
					$scope.showSummary(type, [$scope.selected]);
				};

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {_id:''};
					
					var apiParams = {
						name: $scope.loggedAccount.username,
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForTypeName({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/dns',[
	'app',
], function(app) {
	app.controller("restore_dns_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_dns_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_DOMAINS,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/email',[
	'app',
], function(app) {
	app.controller("restore_email_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_email_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_EMAILS,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/db',[
	'app',
], function(app) {
	app.controller("restore_db_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_db_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);
				
				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_DATABASES,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/dbuser',[
	'app',
], function(app) {
	app.controller("restore_dbuser_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_dbuser_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);
				
				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/ftp',[
	'app',
], function(app) {
	app.controller("restore_ftp_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts", "permissions", "alert", "popup",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts, permissions, alert, popup) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_ftp_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);
				
				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_FTP,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});
define('controllers_enduser/restore/ssl',[
	'app',
], function(app) {
	app.controller("restore_ssl_enduser",
		["$rootScope", "$scope", "$routeParams", "$location", "$timeout", "$interval", "api", "meta", "lang", "consts",
			function($rootScope, $scope, $routeParams, $location, $timeout, $interval, api, meta, lang, consts) {

				$scope.backups = [];
				$scope.selected = {};
				$scope.files = {};
				
				meta = meta.new("enduser_ssl_backups");
				$scope.meta = meta;
				$scope.metaData = meta.getData();

				meta.setSortReverse(false);
				if(!meta.getSortBy()) meta.setSortBy("created");
				if(!meta.getSortDirection()) meta.setSortDirection("desc");
				meta.setPageSizes([10,25,50,100]);
				meta.setPageSize(10);
				meta.setSortFields(["username", "owner"]);
				meta.setTotalItems($scope.backups.length);

				$scope.fetch = function () {

					$scope.backups = [];
					$scope.selected = {};
					
					var apiParams = {
						type: consts.BACKUP_TYPE_ACCOUNT,
						contains: consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES,
						account_id: $scope.loggedAccount._id,
						skip: meta.getSkip(),
						limit: meta.getPageSize(),
						filter: meta.getFilter(),
						sort: {},
						find: {}
					};

					apiParams.sort[meta.getSortBy()] = meta.getSortDirectionInt();

					api.listBackupForType({
						data: apiParams,
						success: function (data) {

							meta.setTotalItems(data.total);
							meta.calculate(data.backups);

							for(var i = 0; i < data.backups.length; i++) {

								var names = [];
								for(var j = 0; j < data.backups[i].schedules.length; j++) names.push(consts.SCHEDULE_TYPES[data.backups[i].schedules[j]]);
								data.backups[i].schedules_names = names.join(",");
								$scope.backups.push(data.backups[i]);
							}
						}
					});
				};
				
				$timeout($scope.fetch);
			}
		]
	);
});


define('controllers_enduser/backups',['app'], function(app) {
	
	app.controller("backups_enduser",
		["$uibModalInstance","$rootScope", "$scope", "$q", "$location", "$timeout", "api", "meta", "util", "permissions", "consts", "lang", "alert", "popup", "summary", "items", "files", "section",
			function ($uibModalInstance, $rootScope, $scope, $q, $location, $timeout, api, meta, util, permissions,  consts, lang, alert, popup, summary, items, files, section) {

				$scope.loading = false;
				$scope.accountData = $scope.loggedAccount;
				$scope.items = items;
				$scope.files = files;
				$scope.list = {};
				$scope.list_checked = {};
				$scope.summary_gotoqueue = true;
				$scope.summary_type = summary;
				$scope.summary_tpl = $scope.includePath('backups' + summary + 'Summary', 'views_enduser');
				$scope.restore_conditions = [];
				$scope.conditions = {};
				$scope.options = {
					package: '' 
				};
				$scope.encryption = { encrypted: false, key: '' };

				$scope.noPermissions = [];
				
				if(section._id === 'full') {
					if(!permissions.canManageFileBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_HOMEDIR);
					if(!permissions.canManageCronBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS);
					if(!permissions.canManageDatabaseBackups) {
						$scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_DATABASES);
						$scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS);
					}
					if(!permissions.canManageDNSZoneBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_DOMAINS);
					if(!permissions.canManageCertificateBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES);
					if(!permissions.canManageEmailBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_EMAILS);
					if(!permissions.canManageFTPBackups) $scope.noPermissions.push(consts.BACKUP_TYPE_ACCOUNT_FTP);
				}


				for (var i = 0; i < $scope.items.length; i++) {
					var backup = $scope.items[i];
					backup.checked = true;
					if($scope.list[backup.backup_contains] === undefined) $scope.list[backup.backup_contains] = [];
					$scope.list[backup.backup_contains].push(backup);
				}
				
				$scope.close = function () { $uibModalInstance.dismiss(); };

				$scope.askForEncryptionKey = function() {
					return $scope.encryption.encrypted && $scope.accountData.backup_type == 1 && $scope.accountData.encryption_key_type == 1;
				};
				
				$scope.ok = function () { $uibModalInstance.close(); };
				
				$scope.calculateSummary = function() {

					var gotData = false;
					$scope.encryption.encrypted = false;
					$scope.list_checked = {};
					for(var contains in $scope.list) {
						for(var i = 0; i < $scope.list[contains].length; i++) {
							var backup = $scope.list[contains][i];
							
							if(!backup.checked) continue;
							if(!$scope.encryption.encrypted && backup.encrypted) $scope.encryption.encrypted = true;
							if($scope.list_checked[contains] === undefined) $scope.list_checked[contains] = [];
							$scope.list_checked[contains].push($scope.list[contains][i]);
							gotData = true;
						}
					}

					if(!gotData) $uibModalInstance.dismiss();
				};

				$scope.gotItems = function(types) {
					for(var i = 0; i < types.length; i++) {
						if($scope.list_checked[types[i]] !== undefined) return true;
					}
					return false;
				};

				$scope.restore = function() {
					
					for(var i = 0; i < $scope.restore_conditions.length; i++) {
						var condition = $scope.restore_conditions[i];
						if($scope.conditions[condition._id] === undefined || !$scope.conditions[condition._id]) {
							alert.error(lang.t("Please accept all restore conditions"));
							return;
						}
					}

					if($scope.askForEncryptionKey() && !$scope.encryption.key) {
						alert.error(lang.t("You must provide \"Backups Private Encryption Key\""));
						return;
					}

					var list = $scope.items;
					var ids = [];
					for(var i = 0; i < list.length; i++) if(list[i].checked) ids.push(list[i]._id);


					var options = util.duplicateObject($scope.options);

					api.addQueueItems({
						data: { type: consts.QUEUE_ITEM_TYPE_RESTORE, items: ids, files: $scope.files, options: options, encryption_key: $scope.encryption.key },
						success: function (data, message) {
							$scope.encryption.key = '';
							alert.success(message);
							$uibModalInstance.close();
							if($scope.summary_gotoqueue) $location.path("/queue");
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.download = function() {

					if($scope.askForEncryptionKey() && !$scope.encryption.key) {
						alert.error(lang.t("You must provide \"Backups Private Encryption Key\""));
						return;
					}

					var list = $scope.items;
					var ids = [];
					for(var i = 0; i < list.length; i++) if(list[i].checked) ids.push(list[i]._id);

					api.addQueueItems({
						data: { type: consts.QUEUE_ITEM_TYPE_DOWNLOAD, items: ids, files: $scope.files, encryption_key: $scope.encryption.key },
						success: function (data, message) {
							$scope.encryption.key = '';
							alert.success(message);
							$uibModalInstance.close();
							if($scope.summary_gotoqueue) $location.path("/queue");
						},
						failed: function (message) {
							alert.error(message);
						}
					});
				};

				$scope.removeItems = function(contains) {
					
					for(var i = 0; i < $scope.list[contains].length; i++) {
						var backup = $scope.list[contains][i];
						backup.checked = false;
					}
					$scope.calculateSummary();
				};

				api.listRestoreConditions({
					data: { find: { disabled: 0 } },
					success: function (data) {
						$scope.restore_conditions = data.conditions;
					}
				});

				$scope.calculateSummary();

			}
		]
	);
});
define('filters/html',["app"], function(app) {
    app.filter("html", ["$sce", function ($sce){
        return function(html) {
            return $sce.trustAs('html', html);
        };
    }]);
});
define('filters/capitalize',["app"], function(app) {
    app.filter("capitalize", function (){
		return function(input, all) {
			return (!!input) ? input.replace((all ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/), function(txt){
			    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
			}) : '';
		};
    });
});
define('filters/executionTime',["app"], function(app) {
    app.filter("executionTime", ["$sce", "lang", function ($sce, lang){
        return function(seconds) {
			seconds = parseInt(seconds);
			if(seconds < 0) return "-";
            if(seconds === 0) return lang.t("Under a Second");

			var time = {
				Day: Math.floor(seconds / 86400),
				Hour: Math.floor(seconds / 3600) % 24,
				Minute: Math.floor(seconds / 60) % 60,
				Second: (seconds % 60)
			};

			if(time['Day']) return lang.t("%s Days and %s Hours and %s Minutes and %s Seconds", time['Day'], time['Hour'], time['Minute'], time['Second'])
			if(time['Hour']) return lang.t("%s Hours and %s Minutes and %s Seconds", time['Hour'], time['Minute'], time['Second'])
			if(time['Minute']) return lang.t("%s Minutes and %s Seconds", time['Minute'], time['Second'])
			if(time['Second']) return lang.t("%s Seconds", time['Second'])
        };
    }]);
});
define('filters/numberFormat',["app"], function(app) {
    app.filter("numberFormat", [function (){
        return function(n, c, d, t) {

			c = isNaN(c = Math.abs(c)) ? 2 : c;
			d = d == undefined ? "." : d;
			t = t == undefined ? "," : t;
			
			var s = n < 0 ? "-" : "";
			var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "";
			var j = (j = i.length) > 3 ? j % 3 : 0;

			return s + (j ? i.substring(0, j) + t : "") + i.substring(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");

		};
    }]);
});


define('services/api',['app'], function (app) {
	app.factory('api', ["$rootScope", "$http", "$location", "cfpLoadingBar", "permissions", "lang", "util",
		function ($rootScope, $http, $location, cfpLoadingBar, permissions, lang, util) {
			
			function _exec(cmd, options) {

				if(options.success === undefined || typeof options.success !== 'function') options.success = function(data, message, system) {};
				if(options.failed === undefined || typeof options.failed !== 'function') options.failed = function(message, system) {};
				if(options.withLoader === undefined) options.withLoader = true;

				if(options.data === undefined) options.data = {};
				options.data.function = cmd;

				if(options.withLoader) cfpLoadingBar.start();

				$http.post(window.PAGE.path.api, options.data).then(function(response) {

					if(response.data.success === undefined && response.data.includes('<html'))
						window.location.reload();

					if(response.data.system.retry_ms > 0) {
						util.sleep(response.data.system.retry_ms);
						_exec(cmd, options);
						return;
					}
					
					if (response.data.message) {
						var args = [];
						args.push('exceptions|:|' + response.data.message);
						if(!response.data.success && response.data.data.length)
							for(var i = 0; i < response.data.data.length; i++) args.push(response.data.data[i]);

						response.data.message = lang.t.apply(lang, args);
					}

					if(response.data.system.licenseIssue || response.data.system.agreement || response.data.system.dr || response.data.system.agreement_panel) {

						var location = '';
						window.PAGE.system = response.data.system;

						if(response.data.system.agreement_panel) location = '/agreementPanel';
						if(response.data.system.dr) location = '/disasterRecovery';
						if(response.data.system.agreement) location = '/agreement';
						if(response.data.system.licenseIssue) {

							if($rootScope.license.status === 'Active') {
								window.PAGE.license = {status:'Invalid',message: response.data.message};
								$rootScope.license = window.PAGE.license;
							}

							location = '/license';
						}

						permissions.init(window.PAGE.permissions);
						$location.path(location);
					}

					if(options.withLoader) cfpLoadingBar.complete();
					
					if(response.data.success) options.success(response.data.data, response.data.message, response.data.system);
					else options.failed(response.data.message, response.data.system);
				}, function () {
					if(options.withLoader) cfpLoadingBar.complete();
				});
			}

			return {
			pluginAPI: function (plugin, func, options) {
				plugin = String(plugin).charAt(0).toUpperCase() + String(plugin).slice(1);
				func = String(func).charAt(0).toUpperCase() + String(func).slice(1);
				return _exec('plugin/' + plugin + '/' + func, options); 
			},
			panel: function (func, options) {
				func = String(func).charAt(0).toUpperCase() + String(func).slice(1);
				return _exec('panel/' + func, options);
			},
			custom: function(func, options) { return _exec(func, options);  },
			getSettings: function (options) {
				var cmd = 'getSettings' + options.data.section[0].toUpperCase()+options.data.section.substr(1);
				delete options.section;
				return _exec(cmd, options);
			},
			manageSettings: function (options) {
				var cmd = 'manageSettings' + options.data.section[0].toUpperCase()+options.data.section.substr(1);
				delete options.section;
				return _exec(cmd, options);
			},

			factoryReset: function (options) { _exec('factoryReset', options); },
			exitDisasterRecovery: function (options) { _exec('exitDisasterRecovery', options); },

			manageRestoreCondition: function (options) { _exec('manageRestoreCondition', options); },
			getRestoreCondition: function (options) { _exec('getRestoreCondition', options); },
			listRestoreConditions: function (options) { _exec('listRestoreConditions', options); },
			deleteRestoreCondition: function (options) { _exec('deleteRestoreCondition', options); },

			createSupportTicketKey: function (options) { _exec('createSupportTicketKey', options); },
			getMyAccount: function (options) { _exec('getMyAccount', options); },
			manageMyAccount: function (options) { _exec('manageMyAccount', options); },

			approveAgreement: function (options) { _exec('approveAgreement', options); },
			getProcessStatus: function (options) { _exec('getProcessStatus', options); },
			fileManager: function (options) { _exec('fileManager', options); },
			getDashboardDetails: function (options) { _exec('getDashboardDetails', options); },
			fileBrowse: function (options) { _exec('fileBrowse', options); },

			getDownload: function (options) { _exec('getDownload', options); },
			listDownloads: function (options) { _exec('listDownloads', options); },
			manageDownloadNotes: function (options) { _exec('manageDownloadNotes', options); },

			createBackupOnDemand: function (options) { _exec('createBackupOnDemand', options); },

			manageSecurityPlugin: function (options) { _exec('manageSecurityPlugin', options); },
			managePlugin: function (options) { _exec('managePlugin', options); },
			getPlugin: function (options) { _exec('getPlugin', options); },
			listPlugins: function (options) { _exec('listPlugins', options); },
			installPlugin: function (options) { _exec('installPlugin', options); },
			uninstallPlugin: function (options) { _exec('uninstallPlugin', options); },
			updatePlugin: function (options) { _exec('updatePlugin', options); },
			listAvailablePlugins: function (options) { _exec('listAvailablePlugins', options); },

			listNotificationIntegrationTypes: function (options) { _exec('listNotificationIntegrationTypes', options); },
			listNotificationIntegrations: function (options) { _exec('listNotificationIntegrations', options); },
			manageNotificationIntegration: function (options) { _exec('manageNotificationIntegration', options); },
			sendNotificationIntegrationTest: function (options) { _exec('sendNotificationIntegrationTest', options); },
			deleteNotificationIntegration: function (options) { _exec('deleteNotificationIntegration', options); },
			getNotificationIntegration: function (options) { _exec('getNotificationIntegration', options); },

			manageHook: function (options) { _exec('manageHook', options); },
			getHook: function (options) { _exec('getHook', options); },
			listHooks: function (options) { _exec('listHooks', options); },
			deleteHook: function (options) { _exec('deleteHook', options); },

			manageTag: function (options) { _exec('manageTag', options); },
			getTag: function (options) { _exec('getTag', options); },
			listTags: function (options) { _exec('listTags', options); },
			deleteTag: function (options) { _exec('deleteTag', options); },

			manageSchedule: function (options) { _exec('manageSchedule', options); },
			getSchedule: function (options) { _exec('getSchedule', options); },
			listSchedules: function (options) { _exec('listSchedules', options); },
			deleteSchedule: function (options) { _exec('deleteSchedule', options); },

			manageQueuePriority: function (options) { _exec('manageQueuePriority', options); },
			getQueuePriority: function (options) { _exec('getQueuePriority', options); },
			listQueuePriorities: function (options) { _exec('listQueuePriorities', options); },
			deleteQueuePriority: function (options) { _exec('deleteQueuePriority', options); },

			getFilePermissions: function (options) { _exec('getFilePermissions', options); },
			listFilePermissions: function (options) { _exec('listFilePermissions', options); },
			manageFilePermissions: function (options) { _exec('manageFilePermissions', options); },
			deleteFilePermissions: function (options) { _exec('deleteFilePermissions', options); },


			getRepository: function (options) { _exec('getRepository', options); },
			listRepositories: function (options) { _exec('listRepositories', options); },
			manageRepository: function (options) { _exec('manageRepository', options); },
			deleteRepository: function (options) { _exec('deleteRepository', options); },
			reloadRepository: function (options) { _exec('reloadRepository', options); },

			getPackage: function (options) { _exec('getPackage', options); },
			listPackages: function (options) { _exec('listPackages', options); },
			listPackagesAvailable: function (options) { _exec('listPackagesAvailable', options); },

			deleteAccountFilter: function (options) { _exec('deleteAccountFilter', options); },
			getAccountFilter: function (options) { _exec('getAccountFilter', options); },
			listAccountFilters: function (options) { _exec('listAccountFilters', options); },
			manageAccountFilter: function (options) { _exec('manageAccountFilter', options); },
			getAccountFilterGroup: function (options) { _exec('getAccountFilterGroup', options); },
			listAccountFilterGroups: function (options) { _exec('listAccountFilterGroups', options); },
			//listPackages: function (options) { _exec('listPackages', options); },
			getAlert: function (options) { _exec('getAlert', options); },
			listAlerts: function (options) { _exec('listAlerts', options); },
			clearAlerts: function (options) { _exec('clearAlerts', options); },

			getPermissions: function (options) { _exec('getPermissions', options); },
			managePermissions: function (options) { _exec('managePermissions', options); },
			resetPermissions: function (options) { _exec('resetPermissions', options); },

			deleteLog: function (options) { _exec('deleteLog', options); },
			getLog: function (options) { _exec('getLog', options); },
			listLogs: function (options) { _exec('listLogs', options); },
			getLogItem: function (options) { _exec('getLogItem', options); },
			listLogItems: function (options) { _exec('listLogItems', options); },

			deleteDestination: function (options) { _exec('deleteDestination', options); },
			getDestination: function (options) { _exec('getDestination', options); },
			listDestinations: function (options) { _exec('listDestinations', options); },
			listDestinationTypes: function (options) { _exec('listDestinationTypes', options); },
			manageDestination: function (options) { _exec('manageDestination', options); },
			manageDestinationState: function (options) { _exec('manageDestinationState', options); },
			validateDestination: function (options) { _exec('validateDestination', options); },
			reindexDestination: function (options) { _exec('reindexDestination', options); },
			measureDestinationSpeed: function (options) { _exec('measureDestinationSpeed', options); },
			genDestinationAuth: function (options) { _exec('genDestinationAuth', options); },

			reassignAccount: function (options) { _exec('reassignAccount', options); },
			listAssignableAccounts: function (options) { _exec('listAssignableAccounts', options); },
			manageAccount: function (options) { _exec('manageAccount', options); },
			manageAccountExcludeList: function (options) { _exec('manageAccountExcludeList', options); },
			getAccount: function (options) { _exec('getAccount', options); },
			getAccountExcludeList: function (options) { _exec('getAccountExcludeList', options); },
			listAccounts: function (options) { _exec('listAccounts', options); },
			listAccountsByFilters: function (options) { _exec('listAccountsByFilters', options); },
			listAccountPackages: function (options) { _exec('listAccountPackages', options); },
			addMultiAccountQueueItems: function (options) { _exec('addMultiAccountQueueItems', options); },
			resetEncryptionKey: function (options) { _exec('resetEncryptionKey', options); },

			addQueueItems: function (options) { _exec('addQueueItems', options); },
			listQueueItems: function (options) { _exec('listQueueItems', options); },
			listQueueGroups: function (options) { _exec('listQueueGroups', options); },
			stopQueueGroup: function (options) { _exec('stopQueueGroup', options); },
			stopAllQueueGroup: function (options) { _exec('stopAllQueueGroup', options); },
			getQueueGroup: function (options) { _exec('getQueueGroup', options); },
			getQueueItem: function (options) { _exec('getQueueItem', options); },
			clearQueue: function (options) { _exec('clearQueue', options); },
			rerunFailedQueueGroup: function (options) { _exec('rerunFailedQueueGroup', options); },

			getBackupItems: function (options) { _exec('getBackupItems', options); },
			getBackupItem: function (options) { _exec('getBackupItem', options); },
			listBackupForTypeName: function (options) { _exec('listBackupForTypeName', options); },
			listBackups: function (options) { _exec('listBackups', options); },
			listBackupForType: function (options) { _exec('listBackupForType', options); },
			listBackupForAccounts: function (options) { _exec('listBackupForAccounts', options); },
			listBackupForDirectories: function (options) { _exec('listBackupForDirectories', options); },
			listBackupForDisasterRecovery: function (options) { _exec('listBackupForDisasterRecovery', options); },

			getMasterEncryptionKey: function (options) { _exec('getMasterEncryptionKey', options); },
			
			deleteSnapshot: function (options) { _exec('deleteSnapshot', options); },

			listShowcase: function (options) { _exec('listShowcase', options); },
			approveShowcase: function (options) { _exec('approveShowcase', options); },

			manageBackupLock: function (options) { _exec('manageBackupLock', options); },
			manageBackupNotes: function (options) { _exec('manageBackupNotes', options); },
			manageMultiBackupLock: function (options) { _exec('manageMultiBackupLock', options); },

			runExtensionDeployment: function (options) { _exec('runExtensionDeployment', options); },
			
			runCloneJobManually: function (options) { _exec('runCloneJobManually', options); },
			duplicateCloneJob: function (options) { _exec('duplicateCloneJob', options); },
			manageCloneJob: function (options) { _exec('manageCloneJob', options); },
			deleteCloneJob: function (options) { _exec('deleteCloneJob', options); },
			getCloneJob: function (options) { _exec('getCloneJob', options); },
			listCloneJobs: function (options) { _exec('listCloneJobs', options); },

			runBackupJobManually: function (options) { _exec('runBackupJobManually', options); },
			duplicateBackupJob: function (options) { _exec('duplicateBackupJob', options); },
			manageBackupJob: function (options) { _exec('manageBackupJob', options); },
			deleteBackupJob: function (options) { _exec('deleteBackupJob', options); },
			getBackupJob: function (options) { _exec('getBackupJob', options); },
			listBackupJobs: function (options) { _exec('listBackupJobs', options); }
		};
	}]);
});


define('services/alert',[
	'app'
], function (app) {
	app.factory('alert', ["$rootScope", function($rootScope) {

		var alert = function(message, state, ttl) {
			if(ttl === undefined) ttl = 10000;
			if($rootScope.alerts === undefined) $rootScope.alerts = [];
			$rootScope.alerts.unshift({message: message, type: state, closeable: true, ttl: ttl });
			
			//window.scrollTo(0, 0);
			//this._init(message, state);
		};

		alert.prototype = {
			/*
			_data: {},
			_init: function(message, state) {
				this._data.message = message;
				this._data.type = state;

				if($rootScope.alerts === undefined) $rootScope.alerts = [];
				$rootScope.alerts.push(this.getData());
			},
			getData: function () {
				return this._data;
			}
			 */
		};

		return {
			success: function (message, ttl) { new alert(message, 'success', ttl); },
			error: function (message, ttl) { new alert(message, 'danger', ttl); },
			warning: function (message, ttl) { new alert(message, 'warning', ttl); },
			info: function (message, ttl) { new alert(message, 'info', ttl); }
		};
	}]);
});


define('services/confirm',[
	'app'
], function (app) {
	app.factory('confirm', ["$rootScope", "$uibModal", "lang", "popupPosition", function($rootScope, $uibModal, lang, popupPosition) {

		return {
			open: function(options) {

				if(options.title === undefined) options.title = lang.t("Are you sure?");
				if(options.message === undefined) options.message = '';
				if(options.cancelLabel === undefined) options.cancelLabel = lang.t('Cancel');
				if(options.confirmLabel === undefined) options.confirmLabel = lang.t('OK');
				if(options.confirm === undefined || typeof options.confirm !== 'function') options.confirm = function () {};
				if(options.cancel === undefined || typeof options.cancel !== 'function') options.cancel = function () {};
				if(options.buttons === undefined) options.buttons = [];

				var model = $uibModal.open({
					animation: true,
					size: "md",
					ariaLabelledBy: 'modal-title',
					ariaDescribedBy: 'modal-body',
					templateUrl: $rootScope.includePath('confirm'),
					controller: 'confirm',
					scope: $rootScope,
					resolve: {
						title: function() { return options.title; },
						message: function() { return options.message; },
						buttons: function () { return options.buttons; },
						labels: function() { return { cancel: options.cancelLabel, confirm: options.confirmLabel }; }
					}
				});

				model.opened.then(function() { popupPosition.update(); });
				model.result.then(options.confirm, options.cancel);
				return model;
			}
		};
	}]);
});


define('services/lang',['app'], function (app) {
	app.factory('lang', ["$i18next", "$location", function ($i18next, $location) {

		var date_formats = {
			short: "D MMM YYYY",
			shorttime: "D MMM YYYY TIME",
			long: "ddd, MMM D, YYYY",
			longtime: "ddd, MMM D, YYYY, TIME"
		};

		return {
			_ns: '',
			setNS: function(ns, scope) {
				var self = this;
				self._ns = ns;
				if(scope !== undefined) {
					scope.$on('$destroy', function() {
						self.resetNS();
					});
				}
			},
			resetNS: function() { this._ns = ''; },
			loadNS: function(ns) { $i18next.loadNamespaces(ns); },
			setDefaultNS: function(ns) {
				this.loadNS(ns);
				$i18next.setDefaultNamespace(ns);
			},
			initNS: function(defaultNS) {
				var ns = $location.path();
				var parts = ns.split('/');
				ns = parts[1];
				if(!ns && defaultNS !== undefined) ns = defaultNS;
				if(ns) this.setDefaultNS(ns);
				else $rootScope.$broadcast('i18nextNSLoad', this._ns);
			},
			t: function() {
				var args = [];
				for(var key in arguments) args.push(arguments[key]);
				var sprintf = args.slice(1);
				var text = (this._ns ? this._ns + "|:|" : '') + args[0];
				if(!sprintf.length) return $i18next.t(text);
				return $i18next.t(text, { postProcess: 'sprintf', sprintf: sprintf });
			},
			d: function (time, format) {

				var date = moment(time);
				if(window.PAGE.info.utcOffset) date.utcOffset(window.PAGE.info.utcOffset);

				if(format === undefined) format = "longtime";
				var key = format;
				format = $i18next.t('date|:|'+key);
				if(format == key) format = "ddd, MMM D, YYYY, |TIME|";
				format = format.replace('|TIME|', window.PAGE.timeformat == 12 ? 'hh:mm A' : 'HH:mm');
				
				return date.format(format);
			}
		};
	}]);
});


define('services/filter',['app'], function (app) {
	app.factory('filter', [function () {

		var filter = function(storage_id) { this._init(storage_id); };

		filter.prototype = {
			_storage_key: undefined,
			_data: {},
			_initStorage: function (storage_id) {
				this._storage_key = "sort_" + storage_id;
				var sort = localStorage.getItem(this._storage_key);
				if(sort === undefined) {
					localStorage.setItem(this._storage_key, JSON.stringify(this._data));
				} else {
					var data = JSON.parse(sort);
					if(data) this._data = data;
				}
			},
			_init: function (storage_id) {
				var defaults = { filter: '' };

				this._data = {};
				for(var i in defaults) this._data[i] = defaults[i];
				if(storage_id !== undefined) this._initStorage(storage_id);
			},
			set: function (key, value) {
				this._data[key] = value;
				localStorage.setItem(this._storage_key, JSON.stringify(this._data));
			},
			get: function (key, defaultValue) { return this._data[key] !== undefined ? this._data[key] : defaultValue; },
			setFilter: function (filter) { this.set('filter', filter); },
			getFilter: function () { return this.get('filter'); },
			setData: function (data) { this._data = data; },
			getData: function () { return this._data; }
		};

		return { new: function (storage_id) { return new filter(storage_id); } };
	}]);
});


define('services/meta',[
	'app'
], function (app) {
	app.factory('meta', ['storage', "lang", function(storage, lang) {

		var meta = function(storage_id) {

			if(storage_id === undefined) throw Error("No storage name provided");
			this._storage_id = storage_id;
			this._storage = storage.create("sort_" + this._storage_id);
			this._noneStorage[this._storage_id] = {};

			for(var key in this._defaults) {
				if(this._noneStorageKeys.indexOf(key) >= 0 || !this._storage.isSet(key)) {
					this.set(key, this._defaults[key]);
				}
			}
		};

		meta.prototype = {
			_defaults: {
				sortReverse: false,
				sortBy: '',
				sortDirection: '',
				sortFields: [],
				filterValue: '',
				maxPages: 3,
				totalItems: 0,
				currentPage: 1,
				pageSize: 25,
				pageSizes: [25, 50, 100, 250, 500],
				start: 0,
				limit: 25,
				itemCountText: undefined
			},
			_noneStorageKeys: ["filterValue"],
			_noneStorage: {},
			_storage_id: undefined,
			_storage: undefined,
			_storage_key: undefined,
			_show_count_text: false,
			_onChangeFunction: function () {}, 
			onChange: function(func) {
				this._onChangeFunction = func;
			},
			set: function (key, value) {
				if(this._noneStorageKeys.indexOf(key) >= 0) {
					this._noneStorage[this._storage_id][key] = value;
				} else {
					this._storage.set(key, value);
					this._storage.save();
				}
				this._onChangeFunction();
			},
			get: function (key, defaultValue) { return this._storage.get(key, defaultValue); },
			setSortReverse: function (sortReverse) { this.set('sortReverse', sortReverse); },
			getSortReverse: function () { return this.get('sortReverse'); },
			setSortBy: function (sortBy) { this.set('sortBy', sortBy); },
			getSortBy: function () { return this.get('sortBy'); },
			setSortDirection: function (sortDirection) { this.set('sortDirection', sortDirection); },
			getSortDirection: function () { return this.get('sortDirection'); },
			getSortDirectionInt: function() { return this.getSortDirection() === "asc" ? 1 : -1; },
			setSortFields: function (sortFields) { this.set('sortFields', sortFields); },
			getSortFields: function () { return this.get('sortFields'); },
			setFilter: function (filter) { this._noneStorage[this._storage_id].filterValue = filter; },
			getFilter: function () { return this._noneStorage[this._storage_id].filterValue; },
			setMaxPages: function (maxPages) { this.set('maxPages', maxPages); },
			getMaxPages: function () { return this.get('maxPages'); },
			setTotalItems: function (totalItems) { this.set('totalItems', parseInt(totalItems)); },
			getTotalItems: function () { return this.get('totalItems'); },
			setCurrentPage: function (currentPage) { this.set('currentPage', currentPage); },
			getCurrentPage: function () { return this.get('currentPage'); },
			setPageSize: function (pageSize) { this.set('pageSize', pageSize); },
			getPageSize: function () { return this.get('pageSize'); },
			setPageSizes: function (pageSizes) { this.set('pageSizes', pageSizes); },
			getPageSizes: function () { return this.get('pageSizes'); },
			setStart: function (start) { this.set('start', start); },
			getStart: function () { return this.get('start'); },
			setLimit: function (limit) { this.set('limit', limit); },
			getLimit: function () { return this.get('limit'); },
			setItemCountText: function (text) { this.set('itemCountText', text); },
			getItemCountText: function () { return this.get('itemCountText'); },
			showItemCountText: function () { this._show_count_text = true; return this._show_count_text; },
			getSkip: function () { return (this.getCurrentPage() - 1) * this.getPageSize(); },
			showPagination: function () { return this.get('showPagination', false); },
			setData: function (data) {
				for(var key in data) {
					if(this._noneStorageKeys.indexOf(key) < 0) continue;
					this._noneStorage[this._storage_id][key] = data[key];
				}
				this._storage.setData(data); 
			},
			getData: function () {
				var data = this._noneStorage[this._storage_id];
				var sdata = this._storage.getData();
				for(var key in sdata) {
					if(this._noneStorageKeys.indexOf(key) >= 0) continue;
					data[key] = sdata[key];
				}
				return data;
			},
			reset: function () {
				this.setCurrentPage(1);
			},
			calculate: function (data) {

				if(data === undefined) data = [];
				if (this.getTotalItems() > this._min(this.getPageSizes())) {
					this.set('showPagination', true);
					var start = (this.getCurrentPage() - 1) * this.getPageSize();
					this.setStart(start + 1);
					//this.setLimit(start + data.length);

				} else {
					// hide pager and pagination
					this.set('showPagination', false);
					this.setStart((data.length === 0) ? 0 : 1);
					this.setLimit(data.length);
				}

				this.setItemCountText(lang.t("Displaying %s to %s out of %s records", this.getStart(), this.getPageSize() * this.getCurrentPage() > this.getTotalItems() ? this.getTotalItems() : this.getPageSize() * this.getCurrentPage(), this.getTotalItems()));
			},
			_min: function (ary) {
				var min = null;
				for(var i; i < ary.length; i++) if(min === null || ary[i] < min) min = ary[i];
				return min === null ? 0 : min;
			}
		};

		return { new: function (storage_id) { return new meta(storage_id); } };
	}]);
});


define('services/storage',[
	'app'
], function (app) {
	app.factory('storage', [function() {
		var STORAGE = function(pool_name) {
			if(pool_name === undefined) throw Error("You must provide pool name");

			this._storage_name = 'JetBackupStorage_' + pool_name;
			this._data = {};

			var storageData = localStorage.getItem(this._storage_name);
			if(storageData === undefined) this.save();
			else this.setData(JSON.parse(storageData));
		};

		STORAGE.prototype = {
			_storage_name: undefined,
			_data: null,
			set: function (key, value) { this._data[key] = value; },
			get: function (key, defaultValue) { return this._data[key] !== undefined ? this._data[key] : defaultValue; },
			isSet: function(key) { return this._data[key] !== undefined; },
			remove: function(key) { delete this._data[key]; },
			save: function() { localStorage.setItem(this._storage_name, JSON.stringify(this._data)); },
			setData: function (data) { if(data) this._data = data; },
			getData: function () { return this._data; },
			destroy: function () { localStorage.removeItem(this._storage_name); this._data={}; }
		};

		return {
			create: function(pool_name) { return new STORAGE(pool_name); },
			delete: function (pool_name) { if(pool_name === undefined) throw Error("You must provide pool name"); localStorage.removeItem('JetBackupStorage_' + pool_name); },
			deleteAll: function () { localStorage.clear(); },
			exists: function (pool_name) { return !!localStorage.getItem('JetBackupStorage_' + pool_name); }
		};
	}]);
});


define('services/permissions',[
	'app'
], function (app) {
	app.factory('permissions', ["PermPermissionStore", "lang", "consts", function(PermPermissionStore, lang, consts) {

		var PERMISSIONS = function() {};

		PERMISSIONS.prototype = {
			_permissions: undefined,
			init: function (permissions) {
				var self = this;

				this._permissions = permissions;

				this.isRoot = !!this._permissions[consts.PERMISSIONS_HAS_ALL_PRIVILEGES];
				this.isReseller = !!(this.isRoot || window.PAGE.account.reseller);
				this.isEnduser = window.PAGE.template === 'enduser';

				this.isShowcase = !!(this.isRoot && window.PAGE.showcase.total_unapproved !== undefined && window.PAGE.showcase.total_unapproved);
				this.isLicenseIssue = !!(window.PAGE.system.licenseIssue !== undefined && window.PAGE.system.licenseIssue);
				this.isDisableUI = !!(window.PAGE.disableui !== undefined && window.PAGE.disableui);
				this.isDisasterRecovery = !!(!this.isDisableUI && window.PAGE.system.dr !== undefined && window.PAGE.system.dr);
				this.isAgreement = !!(!this.isDisableUI && window.PAGE.system.agreement !== undefined && window.PAGE.system.agreement);
				this.isAgreementPanel = !!(!this.isDisableUI && window.PAGE.system.agreement_panel !== undefined && window.PAGE.system.agreement_panel);
				this.isFullScreen = !!(this.isShowcase || this.isLicenseIssue || this.isDisasterRecovery || this.isAgreement || this.isAgreementPanel || this.isDisableUI);
				this.isWPIntegration = !!(this.isRoot && !this.isEnduser && window.PAGE.wp_integrations.length);
				
				this.canManageAccounts = this.check(consts.PERMISSIONS_CAN_MANAGE_ACCOUNTS);
				this.canRestoreBackups = this.check(consts.PERMISSIONS_CAN_RESTORE_BACKUPS);
				this.canDownloadBackups = this.check(consts.PERMISSIONS_CAN_DOWNLOAD_BACKUPS);
				this.canManageFullBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_FULL_BACKUPS);
				this.canManageFileBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_FILE_BACKUPS);
				this.canManageCronBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_CRON_BACKUPS);
				this.canManageEmailBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_EMAIL_BACKUPS);
				this.canManageDatabaseBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_DATABASE_BACKUPS);
				this.canManageCertificateBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_SSL_BACKUPS);
				this.canManageDNSZoneBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_DNSZONES_BACKUPS);
				this.canManageConfigBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_CONFIG_BACKUPS);
				this.canManageBackupJobs = this.check(consts.PERMISSIONS_CAN_MANAGE_BACKUP_JOBS);
				this.canManageCloneJobs = this.check(consts.PERMISSIONS_CAN_MANAGE_CLONE_JOBS);
				this.canManageDestinations = this.check(consts.PERMISSIONS_CAN_MANAGE_DESTINATIONS);
				this.canManageHooks = this.check(consts.PERMISSIONS_CAN_MANAGE_HOOKS);
				this.canManagePermissions = this.check(consts.PERMISSIONS_CAN_MANAGE_PERMISSIONS);
				this.canViewLogs = this.check(consts.PERMISSIONS_CAN_VIEW_LOGS);
				this.canManageLogs = this.check(consts.PERMISSIONS_CAN_MANAGE_LOGS);
				this.canViewAlerts = this.check(consts.PERMISSIONS_CAN_VIEW_ALERTS);
				this.canManageDirectoryBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_DIRECTORY_BACKUPS);
				this.canManageDisasterRecoveryBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_DISASTER_RECOVERY_BACKUPS);
				this.canManageFTPBackups = this.check(consts.PERMISSIONS_CAN_MANAGE_FTP_BACKUPS);
				this.canManageQueue = this.canRestoreBackups || this.canDownloadBackups;
				this.canAccessSocketAPI = this.check(consts.PERMISSIONS_CAN_ACCESS_SOCKET_API);

				this.canManageAccountBackups =
					this.canManageFullBackups ||
					this.canManageFileBackups ||
					this.canManageCronBackups ||
					this.canManageEmailBackups ||
					this.canManageDatabaseBackups ||
					this.canManageCertificateBackups ||
					this.canManageDNSZoneBackups ||
					this.canManageFTPBackups ||
					this.canManageConfigBackups;

				PermPermissionStore.clearStore();

				for(var i in this) {
					if(!/^can/.test(i) && !/^is/.test(i) && !/^has/.test(i)) continue;
					PermPermissionStore.definePermission(i, function(name) {
						if(self[name] === undefined) return false;
						return self[name];
					});
				}
			},
			check: function(perm) {
				return !this.isLicenseIssue && !this.isDisasterRecovery && !this.isShowcase && !this.isAgreement && !this.isAgreementPanel && !this.isDisableUI && !!this._permissions[perm];
			},
			get: function (prem) {
				var perms = {};

				perms[consts.PERMISSIONS_HAS_ALL_PRIVILEGES] 					= {name:lang.t("Has All Privileges"),description:'',warning:lang.t("WARNING: Same as granting root access!")};
				perms[consts.PERMISSIONS_CAN_MANAGE_ACCOUNTS] 					= {name:lang.t("Can Manage Accounts"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_RESTORE_BACKUPS] 					= {name:lang.t("Can Restore Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_DOWNLOAD_BACKUPS] 					= {name:lang.t("Can Download Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_FULL_BACKUPS] 				= {name:lang.t("Can Manage Full Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_FILE_BACKUPS] 				= {name:lang.t("Can Manage File Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_CRON_BACKUPS] 				= {name:lang.t("Can Manage Cron Job Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_EMAIL_BACKUPS] 				= {name:lang.t("Can Manage Email Account Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_DATABASE_BACKUPS] 			= {name:lang.t("Can Manage Database Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_SSL_BACKUPS] 				= {name:lang.t("Can Manage SSL Certificate Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_DNSZONES_BACKUPS] 			= {name:lang.t("Can Manage Domain Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_CONFIG_BACKUPS] 			= {name:lang.t("Can Manage Configuration Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_BACKUP_JOBS] 				= {name:lang.t("Can Manage Backup Jobs"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_CLONE_JOBS] 				= {name:lang.t("Can Manage Clone Jobs"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_DESTINATIONS] 				= {name:lang.t("Can Manage Destinations"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_HOOKS] 						= {name:lang.t("Can Manage Hooks"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_PERMISSIONS] 				= {name:lang.t("Can Manage Permissions"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_VIEW_LOGS] 						= {name:lang.t("Can View Logs"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_LOGS] 						= {name:lang.t("Can Manage Logs"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_VIEW_ALERTS] 						= {name:lang.t("Can View Alerts"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_DIRECTORY_BACKUPS] 			= {name:lang.t("Can Manage Directory Backups"),description:'',warning:lang.t("WARNING: Enabling this permission will give the ability to restore/download files that were backed up in any directory backup job and may contain sensitive information")};
				perms[consts.PERMISSIONS_CAN_MANAGE_DISASTER_RECOVERY_BACKUPS] 	= {name:lang.t("Can Manage Server Backups (BMR)"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_MANAGE_FTP_BACKUPS] 				= {name:lang.t("Can Manage FTP Account Backups"),description:'',warning:''};
				perms[consts.PERMISSIONS_CAN_ACCESS_SOCKET_API] 				= {name:lang.t("Can Access Socket API"),description:'',warning:''};

				return perms[prem] !== undefined ? perms[prem] : null;
			}
		};

		return new PERMISSIONS();
	}]);
});


define('services/popup',[
	'app'
], function (app) {
	app.factory('popup', ["$rootScope", "$uibModal", "lang", "popupPosition", function($rootScope, $uibModal, lang, popupPosition) {

		var popup = function(options) {
			this._init(options);
		};

		popup.prototype = {
			_options: {},
			_init: function (options) {
				this._options = options;
			},
			open: function () {
				if(this._options.size === undefined) this._options.size = 'md';
				if(this._options.resolve === undefined) this._options.resolve = {};
				if(this._options.template === undefined) this._options.template = '';
				if(this._options.templateViews === undefined) this._options.templateViews = '';
				if(this._options.noController === undefined) this._options.noController = false;
				if(this._options.controller === undefined) this._options.controller = '';
				if(this._options.scope === undefined) this._options.scope = $rootScope;

				var modal = $uibModal.open({
					animation: true,
					size: this._options.size,
					ariaLabelledBy: 'modal-title',
					ariaDescribedBy: 'modal-body',
					templateUrl: $rootScope.includePath(this._options.template, this._options.templateViews),
					controller: this._options.noController ? null : (this._options.controller ? this._options.controller : this._options.template),
					scope: this._options.scope,
					resolve: this._options.resolve
				});

				modal.opened.then(function () { popupPosition.update(); });

				return modal;
			}
		};

		return {
			open: function (options) { 
				var i = new popup(options);
				return i.open();
			}
		};
	}]);
});


define('services/popupPosition',[
	'app'
], function (app) {
	app.factory('popupPosition', [function() {

		var popupPosition = function() {
			this._init();
		};

		popupPosition.prototype = {
			_window: window,
			_offset: 0,
			_position: 0,
			_iframe: false,
			_listener_state: undefined,
			_listener_funcs: {
				window: undefined
			},
			_init: function() {
				this._calculate();
			},
			_calculate: function () {
				this._calculateWindow();
				this._listener();
			},
			_calculateWindow: function () {
				
				var self = this;
				self._window = window;
				self._offset = 0;
				self._iframe = false;
				
				while(true) {
					var src = self._window.location.href;
					var newParent = self._window.parent;

					try {
						if(newParent === undefined || newParent === self._window || newParent.document === false) break;
					} catch (e) {
						break;
					}
					self._iframe = true;
					var iframes = newParent.document.getElementsByTagName('iframe');
					self._window = newParent;

					for (var i = 0; i < iframes.length; i++) {
						var iframe = iframes[i];
						if (iframe.src.substr(0, iframe.src.indexOf('?')) !== src.substr(0, src.indexOf('?'))) continue;
						var top = iframe.getBoundingClientRect().top;
						var scrollY = self._window.scrollY;

						if(self._window.popupPosition !== undefined) {
							var popupPosition = self._window.popupPosition;
							if(popupPosition.id !== undefined) {
								var element = self._window.document.getElementById(popupPosition.id);
								if(element !== undefined) {
									top -= element.getBoundingClientRect().top;
									scrollY = element.scrollTop;
								}
							}
						}

						self._offset += scrollY + top;
						break;
					}
				}

				self._window.onresize = function () { self._calculate(); };
			},
			_listener: function () {
				if(!this.insideIframe()) return;
				var self = this;

				var state = (self._window.popupPosition !== undefined && self._window.popupPosition.id !== undefined) ? self._window.popupPosition.id : 'window';
				if(
					self._listener_state && 
					self._listener_state === state &&
					self._listener_funcs[state] !== undefined
				) return;

				var func = undefined;
				var listener = undefined;
				
				if(self._window.popupPosition !== undefined) {
					var popupPosition = self._window.popupPosition;
					if(popupPosition.id !== undefined) {
						var element = self._window.document.getElementById(popupPosition.id);
						if(element !== undefined) {
							func = function () {
								var offset = popupPosition.offset !== undefined ? popupPosition.offset : 0;
								self._scroll(element.scrollTop + offset); 
							};

							listener = element;
						}
					}
				} else {
					func = function () { self._scroll(self._window.scrollY); };
					listener = self._window;
				}

				self._listener_state = state;
				self._listener_funcs[state] = func;
				if(listener !== undefined) listener.addEventListener("scroll", func);
			},
			_scroll: function (scrollY) {
				this._position = scrollY - this._offset;
				if(this._position < 0) this._position = 0;
				this.update();
			},
			update: function () {
				var self = this;

				self._calculate();
				
				if(!self.insideIframe()) return;
				var alert = document.getElementById('alert-floating-container');
				if(alert) alert.style.top = self._position + "px";
				var modalElements = document.getElementsByClassName('modal');
				if(modalElements) for(var i = 0; i < modalElements.length; i++) modalElements[i].style.top = self._position + "px";
			},
			insideIframe: function () { return !!this._iframe; }
		};

		return new popupPosition();
	}]);
});


define('services/consts',[
	'app'
], function (app) {
	app.factory('consts', ["lang", function(lang) {

		var consts = {
			DOCS_URL: "https://docs.jetbackup.com/v5.3",
			CHANGELOG_URL: "https://changelog.jetbackup.com",
			REQUEST_URL: "https://request.jetapps.com",
			FORUM_URL: "https://forum.jetapps.com",
			BLOG_URL: "https://blog.jetapps.com",

			ACCOUNT_FILTER_TYPE_ACCOUNT: 1<<1,
			ACCOUNT_FILTER_TYPE_OWNEDBY: 1<<2,
			ACCOUNT_FILTER_TYPE_SUSPENSION: 1<<3,
			ACCOUNT_FILTER_TYPE_DISK_USAGE: 1<<4,
			ACCOUNT_FILTER_TYPE_INODE_USAGE: 1<<5,
			ACCOUNT_FILTER_TYPE_PACKAGE: 1<<6,
			ACCOUNT_FILTER_TYPE_RANGE: 1<<7,
			ACCOUNT_FILTER_TYPE_REGEX: 1<<8,
			ACCOUNT_FILTER_TYPE_ACCOUNT_TAG: 1<<9,
			ACCOUNT_FILTER_TYPE_ENCRYPTION: 1<<10,
			ACCOUNT_FILTER_TYPE_RESELLER: 1<<11,

			ACCOUNT_FILTER_CONDITION_INCLUDE: 1,
			ACCOUNT_FILTER_CONDITION_EXCLUDE: 2,

			SCHEDULE_DELAY_TYPE_MINUTES: 1,
			SCHEDULE_DELAY_TYPE_HOURS: 2,
			SCHEDULE_DELAY_TYPE_DAYS: 3,

			ACCOUNT_BACKUP_OPTION_EMAIL_STRUCTURE_ONLY: 1,
			ACCOUNT_BACKUP_OPTION_EMAIL_INCLUDE_JUNK: 2,
			ACCOUNT_BACKUP_OPTION_EXCLUDE_DATABASES: 4,

			ACCOUNT_PACKAGE_TYPE_USER: 1,
			ACCOUNT_PACKAGE_TYPE_RESELLER: 2,

			SCHEDULE_WEEK_DAYS_SUNDAY: 1,
			SCHEDULE_WEEK_DAYS_MONDAY: 2,
			SCHEDULE_WEEK_DAYS_TUESDAY: 3,
			SCHEDULE_WEEK_DAYS_WEDNESDAY: 4,
			SCHEDULE_WEEK_DAYS_THURSDAY: 5,
			SCHEDULE_WEEK_DAYS_FRIDAY: 6,
			SCHEDULE_WEEK_DAYS_SATURDAY: 7,

			SCHEDULE_TYPE_HOURLY: 1,
			SCHEDULE_TYPE_DAILY: 2,
			SCHEDULE_TYPE_WEEKLY: 3,
			SCHEDULE_TYPE_MONTHLY: 4,
			SCHEDULE_TYPE_BACKUP_DONE: 5,
			SCHEDULE_TYPE_CLONE_DONE: 10,
			SCHEDULE_TYPE_MANUALLY: 8,
			SCHEDULE_TYPE_SNAPSHOT: 9,

			SCHEDULE_TYPE_MONTHLY_SUFFIX: ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'],

			QUEUE_ITEM_TYPE_BACKUP: 1<<0,
			QUEUE_ITEM_TYPE_RESTORE: 1<<1,
			QUEUE_ITEM_TYPE_DOWNLOAD: 1<<2,
			QUEUE_ITEM_TYPE_REINDEX: 1<<3,
			QUEUE_ITEM_TYPE_CLONE: 1<<4,
			QUEUE_ITEM_TYPE_SECURITY: 1<<5,
			QUEUE_ITEM_TYPE_INTEGRITY_CHECK: 1<<6,
			QUEUE_ITEM_TYPE_SNAPSHOT_DELETE: 1<<7,
			QUEUE_ITEM_TYPE_EXTENSION_INSTALLATION: 1<<8,
			QUEUE_ITEM_TYPE_EXTENSION_QUEUE: 1<<9,

			QUEUE_STATUS_PENDING: 1,
			QUEUE_STATUS_PROCESSING: 2,
			// Backup Account Statuses
			QUEUE_STATUS_BACKUP_ACCOUNT_CONFIG: 30,
			QUEUE_STATUS_BACKUP_ACCOUNT_DOMAINS: 31,
			QUEUE_STATUS_BACKUP_ACCOUNT_CERTIFICATES: 32,
			QUEUE_STATUS_BACKUP_ACCOUNT_FTP: 33,
			QUEUE_STATUS_BACKUP_ACCOUNT_CRON_JOBS: 34,
			QUEUE_STATUS_BACKUP_ACCOUNT_DATABASES: 35,
			QUEUE_STATUS_BACKUP_ACCOUNT_DATABASE_USERS: 36,
			QUEUE_STATUS_BACKUP_ACCOUNT_HOMEDIR: 37,
			QUEUE_STATUS_BACKUP_ACCOUNT_EMAILS: 38,
			QUEUE_STATUS_BACKUP_ACCOUNT_ENCRYPTING: 39,
			QUEUE_STATUS_BACKUP_ACCOUNT_TRANSFERRING: 40,
			// Backup Directories Statuses
			QUEUE_STATUS_BACKUP_DIRECTORY_ENCRYPTING: 50,
			QUEUE_STATUS_BACKUP_DIRECTORY_TRANSFERRING: 51,
			// Backup JBConfig Statuses
			QUEUE_STATUS_BACKUP_JBCONFIG_ENCRYPTION_KEY: 60,
			QUEUE_STATUS_BACKUP_JBCONFIG_DATABASE: 61,
			QUEUE_STATUS_BACKUP_JBCONFIG_FILES: 62,
			QUEUE_STATUS_BACKUP_JBCONFIG_ACCOUNTS_LIST: 63,
			QUEUE_STATUS_BACKUP_JBCONFIG_VERSION: 64,
			QUEUE_STATUS_BACKUP_JBCONFIG_ENCRYPTING: 65,
			QUEUE_STATUS_BACKUP_JBCONFIG_TRANSFERRING: 66,
			
			// Restore Account Statuses
			QUEUE_STATUS_RESTORE_ACCOUNT_CONFIG: 30,
			QUEUE_STATUS_RESTORE_ACCOUNT_DOMAINS: 31,
			QUEUE_STATUS_RESTORE_ACCOUNT_CERTIFICATES: 32,
			QUEUE_STATUS_RESTORE_ACCOUNT_FTP: 33,
			QUEUE_STATUS_RESTORE_ACCOUNT_CRON_JOBS: 34,
			QUEUE_STATUS_RESTORE_ACCOUNT_IMPORTING_DATABASES: 35,
			QUEUE_STATUS_RESTORE_ACCOUNT_DATABASES: 36,
			QUEUE_STATUS_RESTORE_ACCOUNT_DATABASE_USERS: 37,
			QUEUE_STATUS_RESTORE_ACCOUNT_HOMEDIR: 38,
			QUEUE_STATUS_RESTORE_ACCOUNT_EMAILS: 39,
			QUEUE_STATUS_RESTORE_ACCOUNT_POST_RESTORE: 40,
			QUEUE_STATUS_RESTORE_ACCOUNT_PRE_RESTORE: 41,
			// Restore Directories Statuses
			QUEUE_STATUS_RESTORE_DIRECTORY_FILES: 50,
			// Restore JBConfig Statuses
			QUEUE_STATUS_RESTORE_JBCONFIG_DOWNLOADING: 60,
			QUEUE_STATUS_RESTORE_JBCONFIG_EXTRACT: 61,
			QUEUE_STATUS_RESTORE_JBCONFIG_DATABASE: 62,
			QUEUE_STATUS_RESTORE_JBCONFIG_MIGRATE_OWNER: 63,
			QUEUE_STATUS_RESTORE_JBCONFIG_PLUGINS: 64,
			QUEUE_STATUS_RESTORE_JBCONFIG_CONFIGS: 65,
			// Restore Server Backup (BMR) Statuses
			QUEUE_STATUS_BACKUP_DR_DATABASE: 70,
			QUEUE_STATUS_BACKUP_DR_ISO: 71,
			QUEUE_STATUS_BACKUP_DR_ENCRYPTING: 72,
			QUEUE_STATUS_BACKUP_DR_TRANSFERRING: 73,

			// Clone Account Statuses
			QUEUE_STATUS_CLONE_ACCOUNT_PACKAGE: 30,
			QUEUE_STATUS_CLONE_ACCOUNT_CLONING: 31,

			// Download Statuses
			QUEUE_STATUS_DOWNLOAD_DOWNLOADING: 30,
			QUEUE_STATUS_DOWNLOAD_ARCHIVE: 31,
			//
			QUEUE_STATUS_COMPLETED: 100,
			QUEUE_STATUS_PARTIALLY: 101,
			QUEUE_STATUS_FAILED: 102,
			QUEUE_STATUS_ABORTED: 103,
			QUEUE_STATUS_NEVER_FINISHED: 104,

			
			FILE_PERMISSIONS_CATEGORY_HOMEDIR_DATA: 1,
			FILE_PERMISSIONS_CATEGORY_EMAIL_DATA: 2,
			FILE_PERMISSIONS_CATEGORY_FILESYSTEM_DATA: 3,

			ALERT_LEVEL_INFO: 1<<0,
			ALERT_LEVEL_WARNING: 1<<1,
			ALERT_LEVEL_CRITICAL: 1<<2,

			NOTIFICATION_FREQUENCY_REALTIME: 1,
			NOTIFICATION_FREQUENCY_ONCEADAY: 2,

			PLUGIN_PERMISSION_ROOT: 1<<0,
			PLUGIN_PERMISSION_RESELLER: 1<<1,
			PLUGIN_PERMISSION_USER: 1<<2,

			PLUGIN_TYPE_DESTINATION: 'destination',
			PLUGIN_TYPE_NOTIFICATION: 'notification',
			PLUGIN_TYPE_SECURITY: 'security',
			PLUGIN_TYPE_ADDON: 'addon',

			DESTINATION_JOB_TYPE_BACKUP: 1<<0,
			DESTINATION_JOB_TYPE_CLONE: 1<<1,
			
			// Permissions
			PERMISSIONS_HAS_ALL_PRIVILEGES: 0,
			PERMISSIONS_CAN_MANAGE_ACCOUNTS: 1,
			PERMISSIONS_CAN_RESTORE_BACKUPS: 2,
			PERMISSIONS_CAN_DOWNLOAD_BACKUPS: 3,
			PERMISSIONS_CAN_MANAGE_FULL_BACKUPS: 4,
			PERMISSIONS_CAN_MANAGE_FILE_BACKUPS: 5,
			PERMISSIONS_CAN_MANAGE_CRON_BACKUPS: 6,
			PERMISSIONS_CAN_MANAGE_EMAIL_BACKUPS: 7,
			PERMISSIONS_CAN_MANAGE_DATABASE_BACKUPS: 8,
			PERMISSIONS_CAN_MANAGE_SSL_BACKUPS: 9,
			PERMISSIONS_CAN_MANAGE_DNSZONES_BACKUPS: 10,
			PERMISSIONS_CAN_MANAGE_CONFIG_BACKUPS: 11,
			PERMISSIONS_CAN_MANAGE_BACKUP_JOBS: 12,
			PERMISSIONS_CAN_MANAGE_CLONE_JOBS: 21,
			PERMISSIONS_CAN_MANAGE_DESTINATIONS: 13,
			PERMISSIONS_CAN_MANAGE_HOOKS: 14,
			PERMISSIONS_CAN_MANAGE_PERMISSIONS: 15,
			PERMISSIONS_CAN_VIEW_LOGS: 16,
			PERMISSIONS_CAN_MANAGE_LOGS: 17,
			PERMISSIONS_CAN_VIEW_ALERTS: 18,
			PERMISSIONS_CAN_MANAGE_DIRECTORY_BACKUPS: 19,
			PERMISSIONS_CAN_MANAGE_DISASTER_RECOVERY_BACKUPS: 22,
			PERMISSIONS_CAN_MANAGE_FTP_BACKUPS: 20,
			PERMISSIONS_CAN_ACCESS_SOCKET_API: 23,

			// Accounts
			CLONE_TYPE_ACCOUNT: 1,
			CLONE_TYPE_ACCOUNT_CONFIG: 1<<0,
			CLONE_TYPE_ACCOUNT_HOMEDIR: 1<<1,
			CLONE_TYPE_ACCOUNT_DATABASES: 1<<2,
			CLONE_TYPE_ACCOUNT_EMAILS: 1<<3,
			CLONE_TYPE_ACCOUNT_CRON_JOBS: 1<<4,
			CLONE_TYPE_ACCOUNT_DOMAINS: 1<<5,
			CLONE_TYPE_ACCOUNT_CERTIFICATES: 1<<6,
			CLONE_TYPE_ACCOUNT_DATABASE_USERS: 1<<7,
			CLONE_TYPE_ACCOUNT_FTP: 1<<8,

			// Accounts
			BACKUP_TYPE_ACCOUNT: 1,
			BACKUP_TYPE_ACCOUNT_CONFIG: 1<<0,
			BACKUP_TYPE_ACCOUNT_HOMEDIR: 1<<1,
			BACKUP_TYPE_ACCOUNT_DATABASES: 1<<2,
			BACKUP_TYPE_ACCOUNT_EMAILS: 1<<3,
			BACKUP_TYPE_ACCOUNT_CRON_JOBS: 1<<4,
			BACKUP_TYPE_ACCOUNT_DOMAINS: 1<<5,
			BACKUP_TYPE_ACCOUNT_CERTIFICATES: 1<<6,
			BACKUP_TYPE_ACCOUNT_DATABASE_USERS: 1<<7,
			BACKUP_TYPE_ACCOUNT_FTP: 1<<8,

			// Directories
			BACKUP_TYPE_DIRECTORY: 2,
			BACKUP_TYPE_DIRECTORY_FILES: 1<<0,
			BACKUP_TYPE_DIRECTORY_DIRS: 1<<1,

			// JB Config
			BACKUP_TYPE_JB_CONFIG: 3,
			BACKUP_TYPE_JB_CONFIG_DATABASE: 1<<0,
			BACKUP_TYPE_JB_CONFIG_ETC: 1<<1,
			BACKUP_TYPE_JB_CONFIG_VERSION: 1<<2,
			BACKUP_TYPE_JB_CONFIG_ACCOUNTS: 1<<3,
			BACKUP_TYPE_JB_CONFIG_ENCRYPTION: 1<<4,
			BACKUP_TYPE_JB_CONFIG_WIREDTIGER: 1<<5,

			// Server Backup (BMR)
			BACKUP_TYPE_DR: 4,
			BACKUP_TYPE_DR_DATABASE: 1<<0,
			BACKUP_TYPE_DR_ISO: 1<<1,
			BACKUP_TYPE_DR_FILES: 1<<2,

			BACKUP_STRUCTURE_INCREMENTAL: 1<<0,
			BACKUP_STRUCTURE_ARCHIVED: 1<<1,
			BACKUP_STRUCTURE_COMPRESSED: 1<<2,

			HOOK_POSITION_BACKUP: 1,
			HOOK_POSITION_RESTORE: 3,
			HOOK_POSITION_DOWNLOAD: 4,
			HOOK_POSITION_REINDEX: 5,
			HOOK_POSITION_SNAPSHOT: 6,
			HOOK_POSITION_BACKUP_ACCOUNT: 8,
			HOOK_POSITION_CLONE: 9,
			HOOK_POSITION_CLONE_ACCOUNT: 10,

			DATABASE_ENGINE_MYSQL: 1,
			DATABASE_ENGINE_MONGODB: 2,
			DATABASE_ENGINE_PGSQL: 3,

			HOOK_TYPE_POSITION_PRE: 1,
			HOOK_TYPE_POSITION_POST: 2,

			TAG_TYPE_ACCOUNT: 1,

			LOG_TYPE_BACKUP: 1,
			LOG_TYPE_DOWNLOAD: 2,
			LOG_TYPE_RESTORE: 3,
			LOG_TYPE_SYSTEM: 4,
			LOG_TYPE_REINDEX: 5,
			LOG_TYPE_BACKUP_ON_DEMAND: 6,
			LOG_TYPE_CLONE: 7,
			LOG_TYPE_SECURITY: 8,
			LOG_TYPE_EXTENSION: 9,

			LOG_STATUS_COMPLETED: 1,
			LOG_STATUS_FAILED: 2,
			LOG_STATUS_ABORTED: 3,
			LOG_STATUS_PARTIALLY: 4,
			LOG_STATUS_NEVER_FINISHED: 5,
			LOG_STATUS_PROCESSING: 6,

			RECOMMENDED_EXCLUDES_ACCOUNT: {
				'basic': [
					'*.bkup','*.gz','*.jpa','*.log','*.sql','*.tar','*.tar.gz','*.wpress','*.zip','*/.wysiwygPro_*',
					'*/backupbuddy_backups/*','*/cache/smarty/*','*/com_akeeba/backup/*','*/core.[0-9]*','*/error_log',
					'*/var/amasty_fpc/*','*/var/backups/*','*/var/cache/*','*/var/debug/*','*/var/export/*','*/var/import/*',
					'*/var/log/*','*/var/report/*','*/var/session/*','*/var/tmp/*','*/wp-content/cache/*',
					'*/wp-content/wphb-cache/*','*/wp-content/uploads/wpcf7_captcha/*','*/wp-content/widget-cache/*',
					'*/wptsc-cachedir/*','.MirrorSearch','.cpanel/*.sock','.trash','access-logs/*','backup-*.tar.gz',
					'logs/*','public_ftp/*','public_html/cache/*','site-*.tar.gz','softaculous_backups/*','tmp/*','lscache/*'
				],
				'presta': [
					'*-large_default.jpg','*-home_default.jpg','*-medium_default.jpg','*-small_default.jpg','*-cart_default.jpg','*-home_default.jpg',
					'*-thickbox_default.jpg','*-search_default.jpg','public_html/img/**/index.php','**/fileType','**/cache/cachefs/**'
				],
				'wp': [
					'*/wp-content/cache/*','*/wp-content/wphb-cache/*','*/wp-content/uploads/wpcf7_captcha/*','*/wp-content/widget-cache/*',
					'*/wptsc-cachedir/*','*/backupbuddy_backups/*','*/cache/smarty/*','wp-content/w3tc-cache/*','wp-content/uploads/cache/*',
					'wp-content/uploads/wp-rocket/*','wp-content/uploads/wpo-cache/*','wp-content/uploads/wpo-minify/*','wp-content/wflogs/*',
					'wp-content/updraft/*','wp-content/uploads/jetbackup/*', '*.sgbp', 'wp-content/uploads/wp-rocket/'
				],
				'moodle': [
					'moodledata/localcache/*','moodledata/sessions/*','moodledata/temp/*','moodledata/trashdir/*','cache/cachestore_file/*'
				],
				'magento': [
					'media/catalog/product/cache/*','public_html/var/page_cache/*','public_html/var/view_preprocessed/*',
					'public_html/var/session/*','public_html/var/report/*','public_html/generated/*','**/var/cache/mage-tags/*'
				],
			},
			
			PATH_FILTER: /(^[^\/])|(((\/+|^)\.{2})+(\/+|$)|\/{2,})|([`:;\\!$&*()])/,
			PATH_FILTER_PATTERNS: /(((\/+|^)\.{2})+(\/+|$)|\/{2,})|([`:;\\!$&()])/
		};

		consts.DOCS_ADMIN_URL = consts.DOCS_URL + "/adminpanel";
		consts.DOCS_USER_URL =  consts.DOCS_URL + "/userpanel";
		
		consts.ALERT_LEVEL_NAMES = {};
		consts.ALERT_LEVEL_NAMES[consts.ALERT_LEVEL_INFO] = lang.t("Information");
		consts.ALERT_LEVEL_NAMES[consts.ALERT_LEVEL_WARNING] = lang.t("Warning");
		consts.ALERT_LEVEL_NAMES[consts.ALERT_LEVEL_CRITICAL] = lang.t("Critical");

		consts.ALERT_LEVEL_TYPES = {};
		consts.ALERT_LEVEL_TYPES[consts.ALERT_LEVEL_INFO] = 'information';
		consts.ALERT_LEVEL_TYPES[consts.ALERT_LEVEL_WARNING] = 'warning';
		consts.ALERT_LEVEL_TYPES[consts.ALERT_LEVEL_CRITICAL] = 'critical';

		consts.LOG_TYPE_NAMES = {};
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_BACKUP] = lang.t("Backup");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_CLONE] = lang.t("Clone");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_DOWNLOAD] = lang.t("Download");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_RESTORE] = lang.t("Restore");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_REINDEX] = lang.t("Reindex");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_SECURITY] = lang.t("Security");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_SYSTEM] = lang.t("System");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_BACKUP_ON_DEMAND] = lang.t("Backup on Demand");
		consts.LOG_TYPE_NAMES[consts.LOG_TYPE_EXTENSION] = lang.t("Wordpress Installation");

		consts.LOG_STATUS_NAMES = {};
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_COMPLETED] = lang.t("Completed");
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_FAILED] = lang.t("Failed");
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_ABORTED] = lang.t("Aborted");
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_PARTIALLY] = lang.t("Partially Completed");
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_NEVER_FINISHED] = lang.t("Never Finished");
		consts.LOG_STATUS_NAMES[consts.LOG_STATUS_PROCESSING] = lang.t("Processing");

		consts.DATABASE_ENGINE_NAMES = {};
		consts.DATABASE_ENGINE_NAMES[consts.DATABASE_ENGINE_MYSQL] = lang.t("MySQL");
		consts.DATABASE_ENGINE_NAMES[consts.DATABASE_ENGINE_MONGODB] = lang.t("MongoDB");
		consts.DATABASE_ENGINE_NAMES[consts.DATABASE_ENGINE_PGSQL] = lang.t("PostgreSQL");

		consts.QUEUE_STATUS_TO_LOG = {};
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_COMPLETED] = consts.LOG_STATUS_COMPLETED;
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_FAILED] = consts.LOG_STATUS_FAILED;
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_ABORTED] = consts.LOG_STATUS_ABORTED;
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_PARTIALLY] = consts.LOG_STATUS_PARTIALLY;
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_NEVER_FINISHED] = consts.LOG_STATUS_NEVER_FINISHED;
		consts.QUEUE_STATUS_TO_LOG[consts.QUEUE_STATUS_PROCESSING] = consts.LOG_STATUS_PROCESSING;

		consts.DESTINATION_JOB_TYPE_NAMES = {};
		consts.DESTINATION_JOB_TYPE_NAMES[consts.DESTINATION_JOB_TYPE_BACKUP] = lang.t("Backup");
		consts.DESTINATION_JOB_TYPE_NAMES[consts.DESTINATION_JOB_TYPE_CLONE] = lang.t("Clone");

		consts.BACKUP_STRUCTURE_NAMES = {};
		consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_INCREMENTAL] = lang.t("Incremental");
		consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_ARCHIVED] = lang.t("Archived");
		consts.BACKUP_STRUCTURE_NAMES[consts.BACKUP_STRUCTURE_COMPRESSED] = lang.t("Compressed");

		consts.ACCOUNT_FILTER_TYPE_NAMES = {};
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_ACCOUNT] = lang.t("Accounts Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_ACCOUNT_TAG] = lang.t("Account Tags Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_OWNEDBY] = lang.t("Owned By Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_RESELLER] = lang.t("Resellers Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_SUSPENSION] = lang.t("Suspension Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_DISK_USAGE] = lang.t("Disk Space Usage Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_INODE_USAGE] = lang.t("Inodes Usage Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_PACKAGE] = lang.t("Packages Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_RANGE] = lang.t("Characters Range Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_REGEX] = lang.t("Regular Expression Filter");
		consts.ACCOUNT_FILTER_TYPE_NAMES[consts.ACCOUNT_FILTER_TYPE_ENCRYPTION] = lang.t("Encryption Filter");

		consts.BACKUP_ITEMS_TEXT = {};
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = lang.t("Panel Config");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR] = lang.t("Home Dir Files");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_DATABASES] = lang.t("\"%s\" Database");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_EMAILS] = lang.t("\"%s\" Email Account");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS] = lang.t("Cron Jobs");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_DOMAINS] = lang.t("\"%s\" Domains");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES] = lang.t("\"%s\" SSL Certificate");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS] = lang.t("\"%s\" Database User");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_FTP] = lang.t("\"%s\" FTP Account");
		consts.BACKUP_ITEMS_TEXT[consts.BACKUP_TYPE_ACCOUNT_FULL] = lang.t("Full Account");

		consts.BACKUP_DIRECTORY_ITEMS_TEXT = {};
		consts.BACKUP_DIRECTORY_ITEMS_TEXT[consts.BACKUP_TYPE_DIRECTORY_FILES] = lang.t("File \"%s\"");
		consts.BACKUP_DIRECTORY_ITEMS_TEXT[consts.BACKUP_TYPE_DIRECTORY_DIRS] = lang.t("Directory \"%s\"");

		consts.BACKUP_DR_ITEMS_TEXT = {};
		consts.BACKUP_DR_ITEMS_TEXT[consts.BACKUP_TYPE_DR_DATABASE] = lang.t("Database \"%s\"");
		consts.BACKUP_DR_ITEMS_TEXT[consts.BACKUP_TYPE_DR_ISO] = lang.t("ISO Image \"%s\"");
		consts.BACKUP_DR_ITEMS_TEXT[consts.BACKUP_TYPE_DR_FILES] = lang.t("Files \"%s\"");
		
		consts.BACKUP_TYPE_NAMES = {};
		consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_ACCOUNT] = lang.t("Accounts");
		consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_DIRECTORY] = lang.t("Directories");
		consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_JB_CONFIG] = lang.t("JB Config");
		consts.BACKUP_TYPE_NAMES[consts.BACKUP_TYPE_DR] = lang.t("Server Backup (BMR)");

		consts.BACKUP_TYPE_ACCOUNT_FULL =
			consts.BACKUP_TYPE_ACCOUNT_CONFIG |
			consts.BACKUP_TYPE_ACCOUNT_HOMEDIR |
			consts.BACKUP_TYPE_ACCOUNT_DATABASES |
			consts.BACKUP_TYPE_ACCOUNT_EMAILS |
			consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS |
			consts.BACKUP_TYPE_ACCOUNT_DOMAINS |
			consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES |
			consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS |
			consts.BACKUP_TYPE_ACCOUNT_FTP;

		consts.BACKUP_TYPE_ACCOUNT_NAMES = {};
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = lang.t("Panel Config");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR] = lang.t("Home Dir Files");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASES] = lang.t("Databases");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_EMAILS] = lang.t("Email Accounts");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS] = lang.t("Cron Jobs");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DOMAINS] = lang.t("Domains");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES] = lang.t("SSL Certificates");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS] = lang.t("Database Users");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FTP] = lang.t("FTP Accounts");
		consts.BACKUP_TYPE_ACCOUNT_NAMES[consts.BACKUP_TYPE_ACCOUNT_FULL] = lang.t("Full Account");

		consts.CLONE_ITEMS_TEXT = {};
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_CONFIG] = lang.t("Panel Config");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_HOMEDIR] = lang.t("Home Dir Files");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_DATABASES] = lang.t("\"%s\" Database");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_EMAILS] = lang.t("\"%s\" Email Account");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_CRON_JOBS] = lang.t("Cron Jobs");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_DOMAINS] = lang.t("\"%s\" Domains");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_CERTIFICATES] = lang.t("\"%s\" SSL Certificate");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_DATABASE_USERS] = lang.t("\"%s\" Database User");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_FTP] = lang.t("\"%s\" FTP Account");
		consts.CLONE_ITEMS_TEXT[consts.CLONE_TYPE_ACCOUNT_FULL] = lang.t("Full Account");

		consts.CLONE_TYPE_NAMES = {};
		consts.CLONE_TYPE_NAMES[consts.CLONE_TYPE_ACCOUNT] = lang.t("Accounts");

		consts.CLONE_TYPE_ACCOUNT_FULL =
			consts.CLONE_TYPE_ACCOUNT_CONFIG |
			consts.CLONE_TYPE_ACCOUNT_HOMEDIR |
			consts.CLONE_TYPE_ACCOUNT_DATABASES |
			consts.CLONE_TYPE_ACCOUNT_EMAILS |
			consts.CLONE_TYPE_ACCOUNT_CRON_JOBS |
			consts.CLONE_TYPE_ACCOUNT_DOMAINS |
			consts.CLONE_TYPE_ACCOUNT_CERTIFICATES |
			consts.CLONE_TYPE_ACCOUNT_DATABASE_USERS |
			consts.CLONE_TYPE_ACCOUNT_FTP;

		consts.CLONE_TYPE_ACCOUNT_NAMES = {};
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CONFIG] = lang.t("Panel Config");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_HOMEDIR] = lang.t("Home Dir Files");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASES] = lang.t("Databases");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_EMAILS] = lang.t("Email Accounts");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CRON_JOBS] = lang.t("Cron Jobs");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DOMAINS] = lang.t("Domains");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_CERTIFICATES] = lang.t("SSL Certificates");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_DATABASE_USERS] = lang.t("Database Users");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_FTP] = lang.t("FTP Accounts");
		consts.CLONE_TYPE_ACCOUNT_NAMES[consts.CLONE_TYPE_ACCOUNT_FULL] = lang.t("Full Account");

		consts.SCHEDULE_TYPES = {};
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_HOURLY] = lang.t("Hourly");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_DAILY] = lang.t("Daily");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_WEEKLY] = lang.t("Weekly");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_MONTHLY] = lang.t("Monthly");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_BACKUP_DONE] = lang.t("Backup Done");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_MANUALLY] = lang.t("Manually");
		consts.SCHEDULE_TYPES[consts.SCHEDULE_TYPE_SNAPSHOT] = lang.t("Backup on Demand");


		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD = {};
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CONFIG] = lang.t("Panel Config");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_HOMEDIR] = lang.t("Home Dir");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DATABASES] = lang.t("DB");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_EMAILS] = lang.t("Emails");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CRON_JOBS] = lang.t("Cron Jobs");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DOMAINS] = lang.t("Domains");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_CERTIFICATES] = lang.t("Certificates");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_DATABASE_USERS] = lang.t("DB Users");
		consts.BACKUP_TYPE_ACCOUNT_NAMES_WIZARD[consts.BACKUP_TYPE_ACCOUNT_FTP] = lang.t("FTP");

		consts.QUEUE_ITEM_TYPE_NAMES = {};
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP] = lang.t("Backup");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_CLONE] = lang.t("Clone");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE] = lang.t("Restore");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_DOWNLOAD] = lang.t("Download");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_REINDEX] = lang.t("Reindex");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_SECURITY] = lang.t("Security");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_INTEGRITY_CHECK] = lang.t("Backup Cleanup & Integrity Check");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_SNAPSHOT_DELETE] = lang.t("Snapshot Cleanup");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_EXTENSION_INSTALLATION] = lang.t("Wordpress Installation");
		consts.QUEUE_ITEM_TYPE_NAMES[consts.QUEUE_ITEM_TYPE_EXTENSION_QUEUE] = lang.t("Wordpress Mass Deployment");

		consts.SCHEDULE_DELAY_TYPE_NAMES = {};
		consts.SCHEDULE_DELAY_TYPE_NAMES[consts.SCHEDULE_DELAY_TYPE_MINUTES] = lang.t("minutes");
		consts.SCHEDULE_DELAY_TYPE_NAMES[consts.SCHEDULE_DELAY_TYPE_HOURS] = lang.t("hours");
		consts.SCHEDULE_DELAY_TYPE_NAMES[consts.SCHEDULE_DELAY_TYPE_DAYS] = lang.t("days");

		consts.QUEUE_STATUS_NAMES = {};
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_PENDING] = lang.t("Pending");
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_PROCESSING] = lang.t("Processing") + "...";

		consts.QUEUE_STATUS_SUB_NAMES = {};
		// Backup Account Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP] = {};
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_CONFIG] = lang.t("Backing up Panel Configurations");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_DOMAINS] = lang.t("Backing up Domains and DNS");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_CERTIFICATES] = lang.t("Backing up SSL Certificates");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_FTP] = lang.t("Backing up FTP Accounts");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_CRON_JOBS] = lang.t("Backing up Cron Jobs");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_DATABASES] = lang.t("Backing up Databases");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_DATABASE_USERS] = lang.t("Backing up Database Users");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_HOMEDIR] = lang.t("Backing up Home Directory files");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_EMAILS] = lang.t("Backing up Email Accounts");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_ENCRYPTING] = lang.t("Encrypting backup data");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_ACCOUNT_TRANSFERRING] = lang.t("Transferring backup to all destinations");
		// Backup Directories Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DIRECTORY_ENCRYPTING] = lang.t("Encrypting backup data");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DIRECTORY_TRANSFERRING] = lang.t("Transferring backup to all destinations");
		// Backup JBConfig Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_ENCRYPTION_KEY] = lang.t("Backing up JetBackup server Encryption Key");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_DATABASE] = lang.t("Backing up JetBackup Database");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_FILES] = lang.t("Backing up JetBackup Files");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_ACCOUNTS_LIST] = lang.t("Backing up JetBackup Accounts list");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_VERSION] = lang.t("Backing up JetBackup Version");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_ENCRYPTING] = lang.t("Encrypting backup data");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_JBCONFIG_TRANSFERRING] = lang.t("Transferring backup to all destinations");
		// Backup Server Backup (BMR) Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DR_DATABASE] = lang.t("Backing up JetBackup Database");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DR_ISO] = lang.t("Creating ISO image");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DR_ENCRYPTING] = lang.t("Encrypting backup data");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_BACKUP][consts.QUEUE_STATUS_BACKUP_DR_TRANSFERRING] = lang.t("Transferring backup to all destinations");

		// Restore Account Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE] = {};
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_CONFIG] = lang.t("Restoring Panel Configurations");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_DOMAINS] = lang.t("Restoring Domains and DNS");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_CERTIFICATES] = lang.t("Restoring SSL Certificates");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_FTP] = lang.t("Restoring FTP Accounts");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_CRON_JOBS] = lang.t("Restoring Cron Jobs");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_IMPORTING_DATABASES] = lang.t("Importing databases data");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_DATABASES] = lang.t("Restoring Databases");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_DATABASE_USERS] = lang.t("Restoring Database Users");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_HOMEDIR] = lang.t("Restoring Home Directory files");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_EMAILS] = lang.t("Restoring Email Accounts");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_POST_RESTORE] = lang.t("Performing post restore actions");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_ACCOUNT_PRE_RESTORE] = lang.t("Performing pre restore actions");
		// Restore Directories Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_DIRECTORY_FILES] = lang.t("Downloading files");
		// Restore JBConfig Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_DOWNLOADING] = lang.t("Downloading backup");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_EXTRACT] = lang.t("Extracting backup from archive");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_DATABASE] = lang.t("Restoring JetBackup database");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_MIGRATE_OWNER] = lang.t("Migrating objects owner");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_PLUGINS] = lang.t("Installing Plugins");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_RESTORE][consts.QUEUE_STATUS_RESTORE_JBCONFIG_CONFIGS] = lang.t("Restoring JetBackup configuration files");

		// Clone AccountStatuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_CLONE] = {};
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_CLONE][consts.QUEUE_STATUS_CLONE_ACCOUNT_PACKAGE] = lang.t("Packaging account databases and information");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_CLONE][consts.QUEUE_STATUS_CLONE_ACCOUNT_CLONING] = lang.t("Cloning to all destinations");

		// Download Statuses
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_DOWNLOAD] = {};
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_DOWNLOAD][consts.QUEUE_STATUS_DOWNLOAD_DOWNLOADING] = lang.t("Downloading backup");
		consts.QUEUE_STATUS_SUB_NAMES[consts.QUEUE_ITEM_TYPE_DOWNLOAD][consts.QUEUE_STATUS_DOWNLOAD_ARCHIVE] = lang.t("Compressing backup to archive");
		//
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_COMPLETED] = lang.t("Completed");
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_PARTIALLY] = lang.t("Partially Completed");
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_FAILED] = lang.t("Failed");
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_ABORTED] = lang.t("Aborted");
		consts.QUEUE_STATUS_NAMES[consts.QUEUE_STATUS_NEVER_FINISHED] = lang.t("Never Finished");


		consts.SCHEDULE_WEEK_DAYS_NAMES = {};
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_SUNDAY] = lang.t("Sunday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_MONDAY] = lang.t("Monday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_TUESDAY] = lang.t("Tuesday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_WEDNESDAY] = lang.t("Wednesday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_THURSDAY] = lang.t("Thursday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_FRIDAY] = lang.t("Friday");
		consts.SCHEDULE_WEEK_DAYS_NAMES[consts.SCHEDULE_WEEK_DAYS_SATURDAY] = lang.t("Saturday");

		consts.FILE_PERMISSIONS_CATEGORIES = {};
		consts.FILE_PERMISSIONS_CATEGORIES[consts.FILE_PERMISSIONS_CATEGORY_HOMEDIR_DATA] = lang.t("Homedir Data");
		consts.FILE_PERMISSIONS_CATEGORIES[consts.FILE_PERMISSIONS_CATEGORY_EMAIL_DATA] = lang.t("Email Data");
		consts.FILE_PERMISSIONS_CATEGORIES[consts.FILE_PERMISSIONS_CATEGORY_FILESYSTEM_DATA] = lang.t("Filesystem Data");

		consts.PLUGIN_PERMISSION_RESELLER = consts.PLUGIN_PERMISSION_ROOT | consts.PLUGIN_PERMISSION_RESELLER;
		consts.PLUGIN_PERMISSION_USER = consts.PLUGIN_PERMISSION_ROOT | consts.PLUGIN_PERMISSION_RESELLER | consts.PLUGIN_PERMISSION_USER;

		consts.BACKUP_TYPE_DIRECTORY_FULL =
			consts.BACKUP_TYPE_DIRECTORY_FILES |
			consts.BACKUP_TYPE_DIRECTORY_DIRS;

		consts.BACKUP_TYPE_DIRECTORY_NAMES = {};
		consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FILES] = lang.t("Directories (File)");
		consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_DIRS] = lang.t("Directories (Directory)");
		consts.BACKUP_TYPE_DIRECTORY_NAMES[consts.BACKUP_TYPE_DIRECTORY_FULL] = lang.t("Directories");

		consts.BACKUP_TYPE_JB_CONFIG_FULL =
			consts.BACKUP_TYPE_JB_CONFIG_DATABASE |
			consts.BACKUP_TYPE_JB_CONFIG_ETC |
			consts.BACKUP_TYPE_JB_CONFIG_VERSION |
			consts.BACKUP_TYPE_JB_CONFIG_ACCOUNTS |
			consts.BACKUP_TYPE_JB_CONFIG_ENCRYPTION |
			consts.BACKUP_TYPE_JB_CONFIG_WIREDTIGER;

		consts.BACKUP_TYPE_JB_CONFIG_NAMES = {};
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_DATABASE] = lang.t("Database");
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_ETC] = lang.t("ETC Directory");
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_VERSION] = lang.t("Version File");
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_ACCOUNTS] = lang.t("Active Accounts");
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_ENCRYPTION] = lang.t("Encryption Key");
		consts.BACKUP_TYPE_JB_CONFIG_NAMES[consts.BACKUP_TYPE_JB_CONFIG_FULL] = lang.t("JB Config");

		consts.BACKUP_TYPE_DR_FULL =
			consts.BACKUP_TYPE_DR_DATABASE |
			consts.BACKUP_TYPE_DR_ISO |
			consts.BACKUP_TYPE_DR_FILES;

		consts.BACKUP_TYPE_DR_NAMES = {};
		consts.BACKUP_TYPE_DR_NAMES[consts.BACKUP_TYPE_DR_DATABASE] = lang.t("Database");
		consts.BACKUP_TYPE_DR_NAMES[consts.BACKUP_TYPE_DR_ISO] = lang.t("ISO image");
		consts.BACKUP_TYPE_DR_NAMES[consts.BACKUP_TYPE_DR_FILES] = lang.t("Files");
		consts.BACKUP_TYPE_DR_NAMES[consts.BACKUP_TYPE_DR_FULL] = lang.t("Server Backup (BMR)");

		consts.BACKUP_ALLOW_LEGACY_DESTINATION = {};
		consts.BACKUP_ALLOW_LEGACY_DESTINATION[consts.BACKUP_TYPE_ACCOUNT] = true;
		consts.BACKUP_ALLOW_LEGACY_DESTINATION[consts.BACKUP_TYPE_DIRECTORY] = true;
		consts.BACKUP_ALLOW_LEGACY_DESTINATION[consts.BACKUP_TYPE_JB_CONFIG] = true;
		consts.BACKUP_ALLOW_LEGACY_DESTINATION[consts.BACKUP_TYPE_DR] = false;

		consts.BACKUP_ALLOW_LOCAL_DESTINATION = {};
		consts.BACKUP_ALLOW_LOCAL_DESTINATION[consts.BACKUP_TYPE_ACCOUNT] = true;
		consts.BACKUP_ALLOW_LOCAL_DESTINATION[consts.BACKUP_TYPE_DIRECTORY] = true;
		consts.BACKUP_ALLOW_LOCAL_DESTINATION[consts.BACKUP_TYPE_JB_CONFIG] = true;
		consts.BACKUP_ALLOW_LOCAL_DESTINATION[consts.BACKUP_TYPE_DR] = false;

		consts.BACKUP_ALLOW_TIME_BASED_DESTINATION = {};
		consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[consts.BACKUP_TYPE_ACCOUNT] = true;
		consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[consts.BACKUP_TYPE_DIRECTORY] = true;
		consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[consts.BACKUP_TYPE_JB_CONFIG] = true;
		consts.BACKUP_ALLOW_TIME_BASED_DESTINATION[consts.BACKUP_TYPE_DR] = false;

		return consts;
	}]);
});


define('services/util',[
	'app'
], function (app) {
	app.factory('util', [function() {

		var deepDiffMapper = function() {
			return {
				getChanges: function(original, current, removeParams, skipCallback) {
					if(original === undefined || current === undefined) return {};
					if (!this.isObject(original) || !this.isObject(current)) throw 'Invalid argument. Function given, object expected.';
					var changes = {};
					for(var i in current) {
						if(removeParams !== undefined && removeParams.indexOf(i) >= 0) continue;
						if(i === '_id' || (skipCallback !== undefined && typeof skipCallback === 'function' && skipCallback(i))) changes[i] = current[i];
						else if(this.changedValue(original[i], current[i])) changes[i] = current[i];
					}
					return changes;
				},
				isChanged: function(original, current, exclude) {
					if(original === undefined || current === undefined) return false;
					if (!this.isObject(original) || !this.isObject(current)) throw 'Invalid argument. Function given, object expected.';
					for(var i in current) {
						if(exclude !== undefined && exclude.indexOf(i) >= 0) continue;
						if(this.changedValue(original[i], current[i])){
							return true;
						}
					}
					return false;
				},
				changedValue: function(original, current) {

					if (this.isFunction(original) || this.isFunction(current)) throw 'Invalid argument. Function given, object expected.';

					if (this.isValue(current)) {
						if(/^object:[0-9]+$/.test(current)) return false;
						return original !== current;
					}

					var keys = {};
					for (var ckey in current) {
						keys[ckey] = 1;
						if (this.isFunction(current[ckey])) continue;
						if(original === undefined || original[ckey] === undefined) return true;
						if(this.changedValue(original[ckey], current[ckey])) return true;
					}

					for (var okey in original) if(!keys[okey]) return true;

					return false;
				},
				isFunction: function(obj) {
					return {}.toString.apply(obj) === '[object Function]';
				},
				isArray: function(obj) {
					return {}.toString.apply(obj) === '[object Array]';
				},
				isObject: function(obj) {
					return {}.toString.apply(obj) === '[object Object]';
				},
				isDate: function(obj) {
					return {}.toString.apply(obj) === '[object Date]';
				},
				isValue: function(obj) {
					return !this.isObject(obj) && !this.isArray(obj);
				}
			}
		}();

		return {
			sizeToHumanReadable: function(bytes, si, decimals) {
				return (this.sizeToNumber(bytes, si, decimals) + " " + this.sizeToType(bytes, si)).trim();
			},
			sizeToNumber: function(bytes, si, decimals) {
				if(si === undefined) si = false;
				if(decimals === undefined) decimals = 2;
				var unit = si ? 1000 : 1024;
				if (bytes < unit) return bytes;
				var exp = parseInt(Math.log(bytes)/Math.log(unit));
				return (bytes/Math.pow(unit, exp)).toFixed(decimals);
			},
			sizeToType: function(bytes, si) {
				if(si === undefined) si = false;
				var unit = si ? 1000 : 1024;
				if (bytes < unit) return "B";
				var exp = parseInt(Math.log(bytes)/Math.log(unit));
				var pre = (si ? "kMGTPE" : "KMGTPE");
				return pre[exp-1] + "B";
			},
			copyToClipboard: function (text) {
				var copyElement = document.createElement("textarea");
				copyElement.style.position = 'fixed';
				copyElement.style.opacity = '0';
				copyElement.textContent = text;
				var body = document.getElementsByTagName('body')[0];
				body.appendChild(copyElement);
				copyElement.select();
				document.execCommand('copy');
				body.removeChild(copyElement);
			},
			countObj: function (obj) {
				var count = 0;
				for(var key in obj) count++;
				return count;
			},
			saveParams: function (saveData, details, removeParams, skipCallback) {
				return deepDiffMapper.getChanges(details, saveData, removeParams, skipCallback);
			},
			duplicateObject: function (obj) {
				return JSON.parse(JSON.stringify(obj));
			},
			isChanged: function(saveData, details, exclude) {
				return deepDiffMapper.isChanged(details, saveData, exclude);
			},
			sleep: function(ms) {
				const date = Date.now();
				var currentDate = null;
				do {
					currentDate = Date.now();
				} while (currentDate - date < ms);
			},
			versionCompare: function(v1, v2, options) {

				v1 = v1.replace('-', '.');
				v2 = v2.replace('-', '.');
				
				var lexicographical = options && options.lexicographical,
					zeroExtend = options && options.zeroExtend,
					v1parts = v1.split('.'),
					v2parts = v2.split('.');

				function isValidPart(x) {
					return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
				}

				if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
					return NaN;
				}

				if (zeroExtend) {
					while (v1parts.length < v2parts.length) v1parts.push("0");
					while (v2parts.length < v1parts.length) v2parts.push("0");
				}

				if (!lexicographical) {
					v1parts = v1parts.map(Number);
					v2parts = v2parts.map(Number);
				}

				for (var i = 0; i < v1parts.length; ++i) {
					if (v2parts.length == i) {
						return 1;
					}

					if (v1parts[i] == v2parts[i]) {
						continue;
					}
					else if (v1parts[i] > v2parts[i]) {
						return 1;
					}
					else {
						return -1;
					}
				}

				if (v1parts.length != v2parts.length) {
					return -1;
				}

				return 0;
			}
		};
	}]);
});


define('services/filterManager',['app'], function (app) {
	app.factory('filterManager', function () {


		return {

			buildFilters: function(filtersStructure) {

				var arrangedFilters = [];

				// $scope.data.selectedFilters = [];
				var index = 0;
				for (var i = 0; i < filtersStructure.length; i++) {
					if (filtersStructure[i].cond !== undefined && filtersStructure[i].cond === 1) index++;
					if (arrangedFilters[index] === undefined) arrangedFilters[index] = [];
					arrangedFilters[index].push(filtersStructure[i]._id);
				}
				return arrangedFilters;
			},
			reBuildStructure: function(filtersArr) {

				var filtersStructure = [];

				for(var i = 0; i < filtersArr.length; i++) {
					for(var j = 0; j < filtersArr[i].length; j++) {
						var data = { _id: filtersArr[i][j] };
						if(!(i == 0 && j == 0)) data.cond = j == 0 ? 1 : 2;
						filtersStructure.push(data);
					}
				}
				return filtersStructure;
			},
			removeFilter: function(filters, index) {
				filters.splice(index, 1);
				if(index === 0 && filters[0] !== undefined) delete filters[0].cond;
				return filters;
			}


		}

	});
});


define('services/pathManager',['app'], function (app) {
	app.factory('pathManager', [function () {

		var pathManager = function(list) { this._init(list); };

		pathManager.prototype = {
			_tree: {},
			_init: function(list) {
				this._tree = {};
				if(list !== undefined) for(var i = 0; i < list.length; i++) this.addPath(list[i]);
			},
			_getCurrent: function(path) {
				var parts = path.split('/');
				var current = this.getTree();
				while (parts.length) {
					var part = parts.shift();
					if(!part) continue;
					if(current[part] === undefined) return false;
					current = current[part];
				}
				return current;
			},
			_countObj: function (obj) {
				var count = 0;
				for(var key in obj) count++;
				return count;
			},
			isExists: function(path) {
				if(!this._countObj(this.getTree())) return false;
				var current = this._getCurrent(path);
				if(!current) return false;
				return !this._countObj(current);
			},
			isParent: function(path) {
				if(!this._countObj(this.getTree())) return false;
				var current = this._getCurrent(path);
				if(!current) return false;
				return !!this._countObj(current);
			},
			isChildren: function(path) {
				if(!this._countObj(this.getTree())) return false;
				var parts = path.split('/');
				var current = this.getTree();
				while (parts.length) {
					var part = parts.shift();
					if(!part) continue;
					if(current[part] === undefined) return !this._countObj(current);
					current = current[part];
				}
				return false;
			},
			addPath: function (path) {
				var parts = path.split('/');
				var current = this.getTree();
				while (parts.length) {
					var part = parts.shift();
					if(!part) continue;
					if(current[part] === undefined) current[part] = {};
					current = current[part];
				}

				// remove sub folders
				for(var key in current) delete current[key];
			},
			removePath: function (path) {
				// TODO remove from tree
				var parts = path.split('/');
				var current = this.getTree();
				var queue = [];
				while (parts.length) {
					var part = parts.shift();
					if(!part) continue;
					if(current[part] === undefined) return false;
					queue.push({ instance: current, name: part });
					current = current[part];
				}

				if(!queue.length) return;

				var item = queue.pop();

				delete item.instance[item.name];

				while(queue.length) {
					item = queue.pop();
					if(this._countObj(item.instance[item.name]) > 0) return;
					delete item.instance[item.name];
				}

			},
			getSelected: function () {

				var paths = [];
				var tree = this.getTree();
				var queue = [{path: '', obj: tree}];

				while(queue.length) {
					var item = queue.shift();

					for(var key in item.obj) {

						var path = item.path + '/' + key;
						if(this._countObj(item.obj[key])) {
							queue.push({path: path, obj: item.obj[key]});
						} else {
							paths.push(path);
						}
					}
				}

				return paths;
			},
			getTree: function () { return this._tree; }
		};

		return { new: function (list) { return new pathManager(list); } };
	}]);
});


define('directives/pagination',[
	'app'
], function (app, PERMISSIONS) {
	app.directive('pagination', [function() {

		return {

			template:
				'<div class="row search-page-container">\n' +
				'        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">\n' +
				'            <p ng-show="meta.showItemCountText()">{{ meta.getItemCountText() }}</p>\n' +
				'        </div>\n' +
				'        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">\n' +
				'            <div class="pagination-container hidden-xs hidden-sm">\n' +
				'                <page-size id="table_items_per_page"\n' +
				'                        allowed-sizes="meta.getPageSizes()"\n' +
				'                        total-items="meta.getTotalItems()"\n' +
				'                        ng-model="pageSize"\n' +
				'                        show-all="false"\n' +
				'                        ng-show="!hidePageSize && meta.showPagination()">\n' +
				'                </page-size>\n' +
				'                <ul uib-pagination id="table_paginate"\n' +
				'                        total-items="meta.getTotalItems()"\n' +
				'                        ng-model="currentPage"\n' +
				'                        max-size="meta.getMaxPages()"\n' +
				'                        boundary-links="false"\n' +
				'                        direction-links="true"\n' +
				'                        rotate="false"\n' +
				'                        previous-text="<"\n' +
				'                        next-text=">"\n' +
				'                        items-per-page="meta.getPageSize()"\n' +
				'                        ng-show="meta.showPagination()">\n' +
				'                </ul>\n' +
				'            </div>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'    <div class="row hidden-md hidden-lg">\n' +
				'        <div class="col-xs-12">\n' +
				'            <p class="text-right" ng-show="meta.showItemCountText()">{{ meta.getItemCountText() }}</p>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'    <div class="row search-page-container visible-xs-block visible-sm-block hidden-md hidden-lg">\n' +
				'        <div class="col-xs-12 col-sm-12">\n' +
				'            <div class="pagination-container">\n' +
				'                <filter-box id="table_filter_mobile"\n' +
				'                        box-options="filterOptions"\n' +
				'                        ng-model="filter"\n' +
				'                        ng-change="fetch()">\n' +
				'                </filter-box>\n' +
				'                <page-size id="table_items_per_page_mobile"\n' +
				'                        allowed-sizes="meta.getPageSizes()"\n' +
				'                        total-items="meta.getTotalItems()"\n' +
				'                        ng-model="pageSize"\n' +
				'                        show-all="false"\n' +
				'                        ng-show="!hidePageSize && meta.showPagination()">\n' +
				'                </page-size>\n' +
				'                <ul uib-pagination id="table_paginate_mobile"\n' +
				'                        total-items="meta.getTotalItems()"\n' +
				'                        ng-model="currentPage"\n' +
				'                        max-size="0"\n' +
				'                        boundary-links="false"\n' +
				'                        direction-links="true"\n' +
				'                        rotate="false"\n' +
				'                        previous-text="<"\n' +
				'                        next-text=">"\n' +
				'                        items-per-page="meta.getPageSize()"\n' +
				'                        ng-show="meta.showPagination()"\n' +
				'                        class="pagination-small">\n' +
				'                </ul>\n' +
				'            </div>\n' +
				'        </div>\n' +
				'    </div>',
			scope: {
				"meta": "=",
				"fetch": "=",
				"hidePageSize": "="
			},
			link: function (scope) {
				scope.currentPage = scope.meta.getCurrentPage();
				scope.pageSize = scope.meta.getPageSize();

				scope.meta.onChange(function () {
					scope.currentPage = scope.meta.getCurrentPage();
					scope.pageSize = scope.meta.getPageSize();
				});
				
				scope.$watch('currentPage', function (newValue, oldValue) {
					if(newValue === oldValue) return;
					scope.meta.setCurrentPage(scope.currentPage);
					if(scope.meta.getTotalItems() > scope.meta.getSkip()) scope.fetch();
				});

				scope.$watch('pageSize', function (newValue, oldValue) {
					if(newValue === oldValue) return;
					scope.meta.setPageSize(scope.pageSize);
					if(scope.meta.getTotalItems() > scope.meta.getSkip()) scope.fetch();
				});
			}
		};
	}]);
});




define('directives/filterBox',['app'], function (app) {
	app.directive("filterBox", ["$parse", "lang",
		function($parse, lang) {

			return {
				restrict: "EA",
				template: '<div ng-hide="!boxOptions[0]" class="input-group" >\n' +
				'        <span class="input-group-addon">{{filterTitle}}</span>' +
				'        <select id="{{parentID}}_select"\n' +
				'            class="form-control"\n' +
				'            ng-options="filterOpt.value as filterOpt.label for filterOpt in boxOptions"\n' +
				'            ng-model="filter">\n' +
				'        </select>\n' +
				'</div>',
				require: "ngModel",
				replace: true,
				scope: {
					"parentID": "@id",
					"filterTitle": "@",
					"boxOptions": "=boxOptions"
				},

				link: function(scope, element, attrs, ngModel) {

					if (!ngModel) {
						return; // do nothing if no ng-model on the directive
					}

					ngModel.$render = function() {
						if(scope.filterTitle === undefined) scope.filterTitle = lang.t("Filter");
						scope.filter = ngModel.$viewValue;
					};

					scope.$watch("filter", function(newValue, oldValue) {
						if (newValue === oldValue) {
							return; // No update on same value;
						}

						ngModel.$setViewValue(scope.filter);
					});
				}
			};
		}
	]);

});


define('directives/validateField',['app'], function (app) {
	app.directive("validateField", ["$parse", "lang",
		function($parse, lang) {

			return {
				restrict: "A",
				require: "ngModel",
				replace: false,
				scope: {
					min: '@',
					max: '@',
					regex: '@',
					ngModel: '='
				},
				link: function(scope, element, attrs, ngModel) {

					if (!ngModel) return; // do nothing if no ng-model on the directive

					var blinkBorder = function(element) {
						element.css({ borderColor: '#cc0000' });
						setTimeout(function () {
							element.css({ borderColor: 'inherit' });
						}, 2000);
					};


					scope.$watch(function () {
						return ngModel.$modelValue;
					}, function(newValue) {
						scope.oldValue = newValue;
					});

					element.on('blur', function () {

						scope.newValue = ngModel.$viewValue;
						if(scope.newValue === '') return;

						switch(attrs.validateField) {
							case 'int':
								scope.newValue = parseInt(scope.newValue);
								if(scope.min !== undefined && scope.newValue < parseInt(scope.min)) scope.newValue = parseInt(scope.min);
								if(scope.max !== undefined && scope.newValue > parseInt(scope.max)) scope.newValue = parseInt(scope.max);
							break;
							case 'float':
								scope.newValue = parseFloat(scope.newValue);
								if(scope.min !== undefined && scope.newValue < parseFloat(scope.min)) scope.newValue = parseFloat(scope.min);
								if(scope.max !== undefined && scope.newValue > parseFloat(scope.max)) scope.newValue = parseFloat(scope.max);
							break;
							case 'str':
								if(!(new RegExp(scope.regex)).test(scope.newValue)) scope.newValue = '';
								if(scope.max !== undefined && scope.newValue.length > parseInt(scope.max)) scope.newValue = scope.newValue.substr(0, parseInt(scope.max));
							break;
							case 'path':
								var regex = new RegExp(/^(\/[\w\s\d.-]+)+\/?$/);
								if(!regex.test(scope.newValue)) scope.newValue = '';
							break;
							case 'color':
								var regex = new RegExp(/^#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$/);
								if(!regex.test(scope.newValue)) scope.newValue = '';
							break;
							case 'binary':
								var regex = new RegExp(/^((\/[\w\s\d\-]+)+\/?|[\w\-]+)$/);
								if(!regex.test(scope.newValue)) scope.newValue = '';
							break;
							case 'email':
								var regex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
								if(!regex.test(scope.newValue)) scope.newValue = '';
							break;
						}

						if(scope.oldValue == scope.newValue) return;

						blinkBorder(element);
						ngModel.$setViewValue(scope.newValue);
						ngModel.$render();
					});
				}
			};
		}
	]);

});


define('directives/inputDropdown',['app'], function (app) {
	app.directive("inputDropdown", ["$parse", "lang",
		function($parse, lang) {

			return {
				restrict: "E",
				template: '<div class="input-group">' +
				'        <span ng-show="prefix" class="input-group-addon">{{prefixLang}}</span>' +
				'        <select class="form-control"' +
				'            ng-options="value.key as value.label for value in values"' +
				'            ng-model="input">' +
				'        </select>' +
				'        <span ng-show="input == \'CUSTOM\'" class="input-group-addon">-</span>' +
				'		 <span ng-show="input == \'CUSTOM\'" ng-transclude></span>' +
				'        <span class="input-group-addon">{{addonLang}}</span>' +
				'</div>',
				require: "ngModel",
				transclude: true,
				replace: true,
				scope: {
					"addon": "@",
					"prefix": "@",
					"options": "=",
					"ngModel": "="
				},
				link: function(scope, element, attrs, ngModel, transclude) {

					if (!ngModel) return; // do nothing if no ng-model on the directive

					scope.addonLang = scope.addon ? scope.addon : '';
					scope.prefixLang = scope.prefix ? scope.prefix : '';

					scope.values = [];
					Object.keys(scope.options).sort(function(a, b) { return a - b; }).forEach(function(key) {
						var value = key;
						if(value == parseInt(value)) value = parseInt(value);
						scope.values.push({ key: value, label: scope.options[key] });
					});

					scope.values.push({ key: 'CUSTOM', label: lang.t("Custom") });

					ngModel.$render = function() {
						scope.input = ngModel.$viewValue;
						for(var key in scope.options) {
							if(key == parseInt(key)) key = parseInt(key);
							if(key === scope.input) return;
						}
						scope.input = 'CUSTOM';
					};

					scope.$watch("input", function(newValue, oldValue) {
						if (newValue === oldValue || newValue === 'CUSTOM') return;
						ngModel.$setViewValue(scope.input);
					});
				}
			};
		}
	]);

});


define('directives/pageSize',[
	'app',
], function (app) {

	app.directive("pageSize", ["$parse", "pageSizeConfig", "lang",
		function($parse, pageSizeConfig, lang) {
			// A value to assign to the page size entry - 'All'
			var PAGE_SIZE_ALL_VALUE = -1;

			return {
				restrict: "EA",
				template: '<div class="page-size">\n' +
				'    <div ng-hide="autoHide && options[0].value >= totalItems" class="form-group" >\n' +
				'        <label for="{{parentID}}_select" class="title">{{pageSizeTitle}}</label>\n' +
				'        <select id="{{parentID}}_select"\n' +
				'            class="form-control"\n' +
				'            ng-options="size.value as size.label for size in options"\n' +
				'            ng-model="pageSize">\n' +
				'        </select>\n' +
				'    </div>\n' +
				'</div>',
				require: "ngModel",
				replace: true,
				scope: {
					"parentID": "@id",
					"totalItems": "=",
					"allowedSizes": "=",
					"showAll": "=",
					"autoHide": "="
				},

				link: function(scope, element, attrs, ngModel) {

					if (!ngModel) {
						return; // do nothing if no ng-model on the directive
					}

					function getAllowedPageSizes() {
						var meta = {};
						meta.allowedSizes = scope.allowedSizes || pageSizeConfig.allowedSizes;
						meta.totalItems = scope.totalItems || pageSizeConfig.totalItems;
						meta.showAllItems = scope.showAll;

						if (scope.showAll) {
							PAGE_SIZE_ALL_VALUE = scope.totalItems || -1;
						}

						var sizes = meta.allowedSizes.slice(0);

						sizes.sort(function(a, b) {
							return a - b;
						});

						sizes = sizes.map(function(size) {
							return {
								label: size,
								value: size
							};
						});

						if (meta.showAllItems) {

							// Set to 'All' if no other values exist
							sizes.push({
								label: lang.t("All"),
								value: PAGE_SIZE_ALL_VALUE
							});
						}

						// Removing filtering because it's breaking some interfaces
						// When a page doens't have an "All" and has a totalitems
						// less than the smallest size (10) it breaks.

						if (sizes.length === 1 && sizes[0].value === meta.totalItems) {
							scope.pageSize = sizes[0].value;
						} else if (sizes.filter(function(size) {
								return size.value === scope.pageSize;
							}).length === 0) {

							// ensure pageSize is an option, otherwise set to lowest option
							scope.pageSize = sizes[0].value;
						}


						return sizes;

					}

					if (attrs.allowedSizes) {
						scope.$parent.$watch($parse(attrs.allowedSizes), function() {
							scope.options = getAllowedPageSizes();
						});
					}

					if (attrs.totalItems) {
						scope.$parent.$watch($parse(attrs.totalItems), function() {
							scope.options = getAllowedPageSizes();
						});
					}

					if (attrs.showAll) {
						scope.$parent.$watch($parse(attrs.showAll), function() {
							scope.options = getAllowedPageSizes();
						});
					}

					ngModel.$render = function() {
						scope.pageSizeTitle = lang.t("Page Size");
						scope.pageSize = ngModel.$viewValue;
					};

					scope.$watch("pageSize", function(newValue, oldValue) {
						if (newValue === oldValue) {
							return; // No update on same value;
						}
						if (!newValue) {
							return; // New value is null or invalid
						}
						ngModel.$setViewValue(scope.pageSize);
					});

					scope.$watch("totalItems", function() {
						scope.options = getAllowedPageSizes();
					});

					scope.options = getAllowedPageSizes();

				}
			};
		}
	]);

	app.constant("pageSizeConfig", {
		allowedSizes: [10, 20, 50, 100],
		totalItems: 0,
		showAllItems: false
	});

});


define('directives/loadingBox',['app'], function (app) {
	app.directive('loadingBox', function() {
		return {
			restrict: 'E',
			transclude: true,
			template: '<div class="alert alert-info"><em class="fas fa-cog fa-spin"></em> <span ng-transclude></span></div>'
		}
	});
});


define('directives/tooltip',[
	'app',
], function (app) {
	app.directive("tooltip", ["$sce", "$compile", "lang",
		function($sce, $compile, lang) {

			return {
				restrict: "A",
				replace: false,
				terminal: true,
				priority: 1000,
				link: function (scope,element, attrs) {

					var content = attrs.tooltip;
					var regex = /^(top|top-left|top-right|bottom|bottom-left|bottom-right|left|left-top|left-bottom|right|right-top|right-bottom)\|(.*)$/;

					if(regex.test(content)) {
						var parts = content.match(regex);
						element.attr('tooltip-placement', parts[1]);
						content = parts[2];
					}

					regex = /^\{\{(.*)\}\}$/;

					if(regex.test(content)) {
						parts = content.match(regex);
						parts = parts[1].split('.');

						content = scope;
						for(var i = 0; i < parts.length; i++) if(content !== undefined) content = content[parts[i]];
					}

					element.removeAttr("tooltip");

					if(!content) {
						$compile(element)(scope);
						return;
					}

					if(scope.contentHTML === undefined) scope.contentHTML = [];
					var index = scope.contentHTML.length;
					scope.contentHTML[index] = $sce.trustAsHtml("<div style='padding: 5px;'>" + lang.t(content) + "</div>");
					element.attr('uib-tooltip-html', "contentHTML[" + index + "]");
					$compile(element)(scope);
				}
			};
		}
	]);
});


define('directives/sortBy',[
	'app',
], function (app) {
	app.directive("sortBy", ["lang", function(lang) {

		var ASCENDING = "asc";
		var DESCENDING = "desc";
		var DEFAULT_ASCENDING_TITLE = lang.t("Ascending");
		var DEFAULT_DESCENDING_TITLE = lang.t("Descending");

		return {
			template: '<button class="sort-link" ng-click="sort(sortValue)">\n' +
			'    <span ng-transclude></span>\n' +
			'    <span ng-hide="sortMeta.getSortBy() !== sortField">\n' +
			'        <i class="fas" ng-class="{true: \'fa-sort-up\', false: \'fa-sort-down\'}[sortMeta.getSortDirection() == \'asc\']"\n' +
			'           ng-attr-title="{{ getTitle() }}"></i>\n' +
			'    </span>\n' +
			'</button>',
			restrict: "EA",
			transclude: true,
			replace: true,
			scope: {
				sortMeta: "=",
				sortType: "@",
				sortField: "@",
				sortReverse: "@",
				sortAscendingTitle: "@",
				sortDescendingTitle: "@",
				sortReverseDefault: "@",
				onsort: "&"
			},
			compile: function (element, attributes) {

				if (!attributes["sortAscendingTitle"]) {
					attributes["sortAscendingTitle"] = DEFAULT_ASCENDING_TITLE;
				}

				if (!attributes["sortDescendingTitle"]) {
					attributes["sortDescendingTitle"] = DEFAULT_DESCENDING_TITLE;
				}

				return function (scope, element, attributes) {

					/**
					 * Get the title text for the sort direction control.
					 *
					 * @method getTitle
					 */
					scope.getTitle = function () {
						return scope.sortMeta.getSortDirection() === ASCENDING ? attributes["sortAscendingTitle"] : attributes["sortDescendingTitle"];
					};

					/**
					 * Toggle the sort direction on the selected column
					 */
					scope.sort = function () {
						var meta = scope.sortMeta;

						if (meta.getSortBy() === scope.sortField) {
							meta.setSortDirection(meta.getSortDirection() === ASCENDING ? DESCENDING : ASCENDING);
						} else {
							meta.setSortBy(scope.sortField);
							meta.setSortDirection(ASCENDING);
						}

						// Make sure onsort exists on the parent scope before executing it
						var onsort = scope.onsort();
						if (angular.isFunction(onsort)) {
							onsort(meta);
						}
					};
				}
			}
		}
	}]);
});


define('directives/search',[
	'app',
], function (app) {
	app.directive("search", ["lang", function(lang) {

		return {
			restrict: "E",
			template: '<div class="input-group">\n' +
			'    <input type="text"\n' +
			'        id="{{parentID}}_input"\n' +
			'        class="form-control"\n' +
			'        placeholder="{{placeholder}}"\n' +
			'        title="{{title}}"\n' +
			'        ng-model="filterText"\n' +
			'        ng-keyup="clear($event)"\n' +
			'        ng-debounce\n' +
			'        prevent-default-on-enter\n' +
			'        auto-focus="{{autofocus}}"\n' +
			'        aria-label="' + lang.t("Search") + '"/>\n' +
			'    <span class="input-group-btn">\n' +
			'        <button id="{{parentID}}_submit_btn"\n' +
			'            class="btn btn-default"\n' +
			'            ng-click="filterText=\'\'"\n' +
			'            type="button"\n' +
			'            ng-attr-aria-label="{{ !filterText ? ariaLabelSearch : ariaLabelClear }}">\n' +
			'            <span class="fas"\n' +
			'                ng-class="{ \'fa-search\' : !filterText, \'fa-times\' :filterText  }"\n' +
			'                aria-hidden="true">\n' +
			'            </span>\n' +
			'        </button>\n' +
			'    </span>\n' +
			'</div>',
			require: "ngModel",
			replace: true,
			scope: {
				parentID: "@id",
				placeholder: "@?placeholder",
				autofocus: "@?autofocus",
				title: "@?title"
			},
			compile: function() {

				return {
					pre: function(scope, element, attrs) { // eslint-disable-line no-unused-vars
						if (angular.isUndefined(attrs.placeholder)) {
							attrs.placeholder = lang.t("Search");
						}
						if (angular.isUndefined(attrs.title)) {
							attrs.title = lang.t("Search");
						}

						if (angular.isUndefined(attrs.autofocus)) {
							attrs.autofocus = false;
						} else {
							attrs.autofocus = true;
						}

						scope.autofocus = attrs.autofocus;
						scope.placeholder = attrs.placeholder;
						scope.title = attrs.title;
						scope.ariaLabelSearch = lang.t("Search");
						scope.ariaLabelClear = lang.t("Clear");
					},
					post: function(scope, element, attrs, ctrls) { // eslint-disable-line no-unused-vars
						var ngModelCtrl = ctrls;

						if (!ngModelCtrl) {
							return; // do nothing if no ng-model on the directive
						}

						ngModelCtrl.$render = function() {
							scope.filterText = ngModelCtrl.$viewValue;
						};

						scope.clear = function(event) {
							if (event.keyCode === 27) {
								scope.filterText = "";
							}
						};

						var timeout = null;
						scope.$watch("filterText", function() {
							if(timeout !== null) clearTimeout(timeout);
							timeout = setTimeout(function(){
								ngModelCtrl.$setViewValue(scope.filterText);
							}, 300);
						});

					}
				};
			}
		};
	}]);
});


define('directives/alertBox',[
	'app',
], function (app) {
	app.directive("alertBox", ["$timeout", "$compile", "lang",
		function($timeout, $compile, lang) {
			var _counter = 0;
			var ID_DEFAULT_PREFIX = "alert";

			var LABELS = [{
				name: "errorLabel",
				defaultText: lang.t("Error:"),
			}, {
				name: "warnLabel",
				defaultText: lang.t("Warning:")
			}, {
				name: "infoLabel",
				defaultText: lang.t("Information:")
			}, {
				name: "successLabel",
				defaultText: lang.t("Success:")
			}, {
				name: "moreLabel",
				defaultText: lang.t("What went wrong?")
			}];

			var initializeModel = function(hasModel, attrs, modelValue) {
				var data = {};

				if (hasModel) {
					if (angular.isString(modelValue)) {
						data.message = modelValue;
					} else if (angular.isObject(modelValue)) {
						angular.copy(modelValue, data);
					} else {
						throw new TypeError("ngModel must be a string or object.");
					}
				}

				if (!angular.isDefined(data.type)) {
					if (angular.isDefined(attrs.type) && attrs.type) {
						data.type = attrs.type;
					} else {
						data.type = "warning";
					}
				}

				if (angular.isDefined(data.closable)) {
					data.closable = ((data.type === "danger") ? false : data.closable);
				} else if (angular.isDefined(attrs.closable)) {
					data.closable = ((data.type === "danger") ? false : true);
				} else {
					data.closable = false;
				}

				if (angular.isDefined(data.autoClose)) {
					data.autoClose = ((data.type === "danger") ? false : data.autoClose);
				} else if (angular.isDefined(attrs.autoClose)) {
					data.autoClose = ((data.type === "danger") ? false : data.autoClose);
				} else {
					data.autoClose = false;
				}
				if (!angular.isDefined(data.id)) {
					if (!angular.isDefined(attrs.id)) {
						data.id = ID_DEFAULT_PREFIX + _counter++;
					} else {
						data.id = attrs.id;
					}
				}

				if (hasModel && !angular.isDefined(data.message) && !data.message) {
					throw new Error("No message provided in the model's message property.");
				}

				return data;
			};

			var renderBody = function(scope, element, transclude) {

				var type = scope.alert.type;
				var typeBlock = element[0].querySelector(".alert-" + type);
				var messageSpan = typeBlock.querySelector(".alert-body");

				transclude(function(clone) {

					angular.element(messageSpan).append(clone);
				});
			};


			return {
				restrict: "EA",
				template: '<div>\n' +
				'    <div ng-show="alert.type === \'danger\'" class=\'alert alert-danger ng-hide\'>\n' +
				'        <button id="{{\'btnClose_danger_\' + alert.id}}" type=\'button\' class=\'close\' ng-if=\'alert.closeable\' ng-click=\'runClose()\'>&times;</button>\n' +
				'        <button id="{{\'btnMore_danger_\' + alert.id}}" type=\'button\' class=\'btn btn-more btn-link pull-right flip\' ng-if=\'hasToggleHandler\' ng-click=\'runToggleMore()\'>{{moreLabel}}</button>\n' +
				'        <div class=\'alert-message\'>\n' +
					'        <span class=\'fas fa-times-circle\'></span>\n' +
				'            <strong class="alert-title" ng-show="errorLabel">{{errorLabel}}</strong>\n' +
				'            <span class="alert-body"><span id="{{\'txtMessage_danger_\' + alert.id}}" ng-bind-html="alert.message" ng-if="alert && alert.message"></span></span>\n' +
				'            <ul ng-if="alert.list && alert.list.length" class="alert-list">\n' +
				'                <li ng-repeat="value in alert.list">\n' +
				'                    <span id="{{\'txtList_danger_\' + alert.id + \'_\' + $index}}" ng-bind-html="value"></span>\n' +
				'                </li>\n' +
				'            </ul>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'\n' +
				'    <div ng-show="alert.type === \'info\'" class=\'alert alert-info ng-hide\'>\n' +
				'        <button id="{{\'btnClose_info_\' + alert.id}}" type=\'button\' class=\'close\' ng-if=\'alert.closeable\' ng-click=\'runClose()\'>&times;</button>\n' +
				'        <button id="{{\'btnMore_info_\' + alert.id}}" type=\'button\' class=\'btn btn-more btn-link pull-right flip\' ng-if=\'hasToggleHandler\' ng-click=\'runToggleMore()\'>{{moreLabel}}</button>\n' +
				'        <div class=\'alert-message\'>\n' +
					'        <span class=\'fas fa-info-circle\'></span>\n' +
				'            <strong class="alert-title" ng-show="infoLabel">{{infoLabel}}</strong>\n' +
				'            <span class="alert-body"><span id="{{\'txtMessage_info_\' + alert.id}}" ng-bind-html="alert.message" ng-if="alert && alert.message"></span></span>\n' +
				'            <ul ng-if="alert.list && alert.list.length" class="alert-list">\n' +
				'                <li ng-repeat="value in alert.list">\n' +
				'                    <span id="{{\'txtList_info_\' + alert.id + \'_\' + $index}}" ng-bind-html="value"></span>\n' +
				'                </li>\n' +
				'            </ul>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'\n' +
				'    <div ng-show="alert.type === \'success\'" class=\'alert alert-success ng-hide\'>\n' +
				'        <button id="{{\'btnClose_success_\' + alert.id}}" type=\'button\' class=\'close\' ng-if=\'alert.closeable\' ng-click=\'runClose()\'>&times;</button>\n' +
				'        <button id="{{\'btnMore_success_\' + alert.id}}" type=\'button\' class=\'btn btn-more btn-link pull-right flip\' ng-if=\'hasToggleHandler\' ng-click=\'runToggleMore()\'>{{moreLabel}}</button>\n' +
				'        <div class=\'alert-message\'>\n' +
					'        <span class=\'fas fa-check-circle\'></span>\n' +
				'            <strong class="alert-title" ng-show="successLabel">{{successLabel}}</strong>\n' +
				'            <span class="alert-body"><span id="{{\'txtMessage_success_\' + alert.id}}" ng-bind-html="alert.message" ng-if="alert && alert.message"></span></span>\n' +
				'            <ul ng-if="alert.list && alert.list.length" class="alert-list">\n' +
				'                <li ng-repeat="value in alert.list">\n' +
				'                    <span id="{{\'txtList_success_\' + alert.id + \'_\' + $index}}" ng-bind-html="value"></span>\n' +
				'                </li>\n' +
				'            </ul>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'\n' +
				'    <div ng-show="alert.type === \'warning\'" class=\'alert alert-warning ng-hide\'>\n' +
				'        <button id="{{\'btnClose_warning_\' + alert.id}}" type=\'button\' class=\'close\' ng-if=\'alert.closeable\' ng-click=\'runClose()\'>&times;</button>\n' +
				'        <button id="{{\'btnMore_warning_\' + alert.id}}" type=\'button\' class=\'btn btn-more btn-link pull-right flip\' ng-if=\'hasToggleHandler\' ng-click=\'runToggleMore()\'>{{moreLabel}}</button>\n' +
				'        <div class=\'alert-message\'>\n' +
					'        <span class=\'fas fa-exclamation-circle\'></span>\n' +
				'            <strong class="alert-title" ng-show="warnLabel">{{warnLabel}}</strong>\n' +
				'            <span class="alert-body"><span id="{{\'txtMessage_warning_\' + alert.id}}" ng-bind-html="alert.message" ng-if="alert && alert.message"></span></span>\n' +
				'            <ul ng-if="alert.list && alert.list.length" class="alert-list">\n' +
				'                <li ng-repeat="value in alert.list">\n' +
				'                    <span id="{{\'txtList_warning_\' + alert.id + \'_\' + $index}}" ng-bind-html="value"></span>\n' +
				'                </li>\n' +
				'            </ul>\n' +
				'        </div>\n' +
				'    </div>\n' +
				'</div>',
				transclude: true,
				replace: true,
				require: "?ngModel",
				scope: {
					close: "&onClose",
					toggleMore: "&onToggleMore",
					autoClose: "=",
					errorLabel: "@",
					warnLabel: "@",
					infoLabel: "@",
					successLabel: "@",
					moreLabel: "@"
				},
				compile: function(element, attrs) {

					LABELS.forEach(function(label) {
						if (!angular.isDefined(attrs[label.name])) {
							attrs[label.name] = label.defaultText;
						}
					});

					return function(scope, element, attrs, ngModelCtrl, transclude) {

						if (ngModelCtrl) {
							ngModelCtrl.$formatters.push(function(modelValue) {
								return initializeModel(true, attrs, modelValue);
							});

							ngModelCtrl.$render = function() {
								scope.alert = ngModelCtrl.$viewValue;
							};
						} else {
							scope.alert = initializeModel(false, attrs);
							renderBody(scope, element, transclude);
						}

						scope.$watch("alert.label", function(newVal) {
							if ( angular.isDefined(newVal) ) {
								LABELS.forEach(function(label) {
									attrs.$set(label.name, newVal);
								});
							}
						});
						scope.runClose = function() {
							if (scope.timer) {
								var timer = scope.timer;
								scope.timer = null;
								delete scope.timer;
								$timeout.cancel(timer);
							}

							scope.$emit("closeAlertCalled", {
								id: scope.alert.id
							});

							scope.alert.type = '';
							//ngModel.$setViewValue(scope.type);
							// scope.close();
						};

						var msecs = scope.autoClose ? parseInt(scope.autoClose, 10) : null;
						if (msecs && !isNaN(msecs)) {
							scope.timer = $timeout(function() {
								scope.runClose();
							}, msecs);
						}

						scope.hasToggleHandler = angular.isDefined(attrs.onToggleMore);
						scope.showMore = false;
						scope.runToggleMore = function() {
							scope.showMore = !scope.showMore;
							var e = {
								id: scope.alert.id,
								show: scope.showMore
							};
							scope.$emit("toggleMoreAlertCalled", e);
							scope.toggleMore(e);
						};

					};
				}
			};
		}
	]);

});


define('directives/navigation',[
	'app'
], function (app) {
	app.directive('navigation', ["$rootScope", "$location", "lang", "permissions", function($rootScope, $location, lang, permissions) {

		return {

			template:
				'<li aria-label="{{ option.label }}" ng-repeat="option in options" ng-if="option.permissions" ng-class="{ \'active\': active == option.class }" > ' +
					'<a href="{{url}}{{option.href}}" ng-click="changePath(option.href)" tooltip-placement="right" tooltip-enable="collapsed" uib-tooltip="{{ option.label }}" > '+
						'<em aria-hidden="true" class="{{ option.icon }}"></em>' +
						'<span>{{ option.label }}</span>' +
					'</a>'+
				'</li>',
			scope: {
				"collapsed": "=",
				"active": "="
			},
			link: function (scope) {

				var account = window.PAGE.account;

				scope.changePath = function(path) { $location.path(path); };
				scope.url = $rootScope.primaryURL;
				scope.options = [
					{label: lang.t("Dashboard"), 			href: "/", 				class: 'Dashboard', 	icon: 'fas fa-home', permissions: true },
					{label: lang.t("Accounts"), 			href: "/accounts", 		class: 'Accounts', 		icon: 'fas fa-users', permissions: !permissions.isEnduser && permissions.canManageAccounts },
					{label: lang.t("Destinations"), 		href: "/destinations", 	class: 'Destinations', 	icon: 'fas fa-folder', permissions: !permissions.isEnduser && permissions.canManageDestinations },
					{label: lang.t("Backup Jobs"),			href: "/backupJobs", 	class: 'BackupJobs', 	icon: 'fas fa-cubes', permissions: !permissions.isEnduser && permissions.canManageBackupJobs },
					{label: lang.t("Clone Jobs"),			href: "/cloneJobs", 	class: 'CloneJobs', 	icon: 'fas fa-clone', permissions: !permissions.isEnduser && permissions.canManageCloneJobs },
					{label: lang.t("Restore & Download"),	href: "/restore" + (permissions.isEnduser ? '/full' : '/singleaccount'), 		class: 'Restore', 		icon: 'fas fa-sync', permissions: permissions.canManageAccountBackups },
					{label: lang.t("Downloads"),			href: "/downloads", 	class: 'Downloads', 	icon: 'fas fa-cloud-download-alt', permissions: permissions.canDownloadBackups },
					{label: lang.t("Alerts"), 				href: "/alerts", 		class: 'Alerts', 		icon: 'fas fa-exclamation-triangle', permissions: permissions.canViewAlerts },
					{label: lang.t("Queue"), 				href: "/queue", 		class: 'Queue', 		icon: 'fas fa-clock', permissions: permissions.canManageQueue },
					{label: lang.t("Logs"), 				href: "/logs", 			class: 'Logs', 			icon: 'fas fa-file-alt', permissions: !permissions.isEnduser && permissions.canViewLogs },
					{label: lang.t("Permissions"), 			href: "/permissions", 	class: 'Permissions', 	icon: 'fas fa-users-cog', permissions: !permissions.isEnduser && permissions.canManagePermissions },
					{label: lang.t("Hooks"), 				href: "/hooks", 		class: 'Hooks', 		icon: 'fas fa-flag', permissions: !permissions.isEnduser && permissions.canManageHooks },
					{label: lang.t("Security"), 			href: "/security", 		class: 'Security', 		icon: 'fas fa-fingerprint', permissions: !permissions.isEnduser && permissions.isRoot },
					{label: lang.t("Plugins"), 				href: "/plugins", 		class: 'Plugins', 		icon: 'fas fa-puzzle-piece', permissions: !permissions.isEnduser && permissions.isRoot },
					{label: lang.t("Wordpress Integration"),href: "/extension", 	class: 'Extension', 	icon: 'fab fa-wordpress', permissions: permissions.isWPIntegration }
				];

				scope.pluginsPositions = {};
				scope.lastPosition = (scope.options.length-1);

				var addPlugin = function (plugin) {
					scope.lastPosition++;
					scope.options.splice(scope.lastPosition, 0, {
						label: plugin.name,
						href: "/plugin/"+plugin.code,
						class: "Plugin" + plugin.code,
						icon: plugin.icon ? plugin.icon : 'fas fa-puzzle-piece',
						permissions: (plugin.visible && !plugin.disabled)
					});
					scope.pluginsPositions[plugin._id] = scope.lastPosition;
				};

				for(var _id in $rootScope.plugins) addPlugin($rootScope.plugins[_id]);

				$rootScope.$watch('plugins', function () {
					for(var _id in $rootScope.plugins) {
						var plugin = $rootScope.plugins[_id];
						if(scope.pluginsPositions[_id] === undefined) addPlugin(plugin);
						else scope.options[scope.pluginsPositions[_id]].permissions = (plugin.visible && !plugin.disabled);
					}
				}, true);

				scope.options.push({label: lang.t("Settings"), 			href: "/settings", 		class: 'Settings', 		icon: 'fas fa-cog', permissions: !permissions.isEnduser && permissions.isRoot });
			}
		};
	}]);
});




require([
	'app',
	'controllers/404',
	'controllers/myAccount',
	'controllers/agreement',
	'controllers/agreementPanel',
	'controllers/dashboard',
	'controllers/alerts',
	'controllers/accounts',
	'controllers/accountsOrphans',
	'controllers/accountManage',
	'controllers/accountReassign',
	'controllers/accountExcludeListSelection',
	'controllers/modifyDatabasesExcludes',
	'controllers/destinations',
	'controllers/destinationManage',
	'controllers/disasterRecovery',
	'controllers/disasterRecovery/selection',
	'controllers/disasterRecovery/destination',
	'controllers/disasterRecovery/settings',
	'controllers/disasterRecovery/backups',
	'controllers/disasterRecovery/backups',
	'controllers/disasterRecovery/accounts',
	'controllers/restoreConditions',
	'controllers/restoreConditionManage',
	'controllers/backupJobs',
	'controllers/backupJobManage',
	'controllers/cloneJobs',
	'controllers/cloneJobManage',
	'controllers/permissions',
	'controllers/schedules',
	'controllers/scheduleManage',
	'controllers/scheduleManagePopup',
	'controllers/scheduleSelection',
	'controllers/queue',
	'controllers/queueItems',
	'controllers/queueLogViewer',
	'controllers/queuePriorities',
	'controllers/queuePriorityManage',
	'controllers/security',
	'controllers/extension',
	'controllers/support',
	'controllers/repositories',
	'controllers/repositoryManage',
	'controllers/filePermissions',
	'controllers/filePermissionsManage',
	'controllers/hooks',
	'controllers/hookManage',
	'controllers/tags',
	'controllers/tagManage',
	'controllers/tagsSelection',
	'controllers/destinationsSelection',
	'controllers/backupJobsSelection',
	'controllers/cloneJobsSelection',
	'controllers/backupLockSelection',
	'controllers/plugins',
	'controllers/packages',
	'controllers/showcase',
	//'controllers/addons',
	'controllers/plugin',
	'controllers/pluginManage',
	'controllers/logs',
	'controllers/logViewer',
	'controllers/logItems',
	'controllers/settings',
	'controllers/settings/binary',
	'controllers/settings/general',
	'controllers/settings/notification',
	'controllers/settings/notificationManage',
	'controllers/settings/performance',
	'controllers/settings/resource',
	'controllers/settings/privacy',
	'controllers/settings/restore',
	'controllers/settings/snapshots',
	'controllers/settings/update',
	'controllers/fileManager',
	'controllers/fileManagerPopup',
	'controllers/fileBrowse',
	'controllers/downloads',
	'controllers/accountSelection',
	'controllers/restore',
	'controllers/restoreMultiAccount',
	'controllers/restoreSingleAccount',
	'controllers/restoreDirectories',
	'controllers/restoreDisasterRecovery',
	'controllers/accountBackups',
	'controllers/accountDownloads',
	'controllers/accountFilters',
	'controllers/accountFilterManage',
	'controllers/accountFilterManagePopup',
	'controllers/accountFilterGroupManage',
	'controllers/accountFilterGroupManagePopup',
	'controllers/accountFilterGroups',
	'controllers/accountFilterGroupSelection',
	'controllers/accountsSelection',
	'controllers/accountPackagesSelection',
	'controllers/resellersSelection',
	'controllers/confirm',

	'controllers_enduser/dashboard',
	'controllers_enduser/restore',
	'controllers_enduser/restore/full',
	'controllers_enduser/restore/files',
	'controllers_enduser/restore/cron',
	'controllers_enduser/restore/dns',
	'controllers_enduser/restore/email',
	'controllers_enduser/restore/db',
	'controllers_enduser/restore/dbuser',
	'controllers_enduser/restore/ftp',
	'controllers_enduser/restore/ssl',
	'controllers_enduser/backups',

	'filters/html',
	'filters/capitalize',
	'filters/executionTime',
	'filters/numberFormat',
	'services/api',
	'services/alert',
	'services/confirm',
	'services/lang',
	'services/filter',
	'services/meta',
	'services/storage',
	'services/permissions',
	'services/popup',
	'services/popupPosition',
	'services/consts',
	'services/util',
	'services/filterManager',
	'services/pathManager',
	'directives/pagination',
	'directives/filterBox',
	'directives/validateField',
	'directives/inputDropdown',
	'directives/pageSize',
	'directives/loadingBox',
	'directives/tooltip',
	'directives/sortBy',
	'directives/search',
	'directives/alertBox',
	'directives/navigation'
], function (app) {
	angular.bootstrap(document, ['JetBackupApp']);
});
define("main", function(){});

}());